Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 5085 | Accepted: 1991 |
Description
Input
Output
Sample Input
0 0 1 1 1 0 0 1 1 0 1 1 0 0 0 0 0 0 0 0
Sample Output
3
Hint
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 [after flipping bowl 11]
题意:有20个为0或1的整数,已知改变i位置的数字时,会同时改变i-1和i+1位置的数字,改变效应——0->1 或者 1->0。问你最少的操作使得20个整数全为0。
思路:20个方程,20个变元——高斯消元 + 妆压枚举自由变元 就可以了。
AC代码:
#include <cstdio> #include <cstring> #include <algorithm> #define MAXN 25 #define INF 0x3f3f3f3f using namespace std; int a[MAXN][MAXN]; int free_rec[MAXN]; int x[MAXN]; int equ, var; void init_a() { equ = var = 20; memset(a, 0, sizeof(a)); for(int i = 1; i < 20; i++) { scanf("%d", &a[i][var]), a[i][var] ^= 0; a[i][i] = 1; a[i][i-1] = 1; if(i < 19) a[i][i+1] = 1; } } int Gauss() { int max_r, k; int col = 0; int num = 0; for(k = 0; k < equ && col < var; k++, col++) { max_r = k; for(int i = k+1; i < equ; i++) if(a[i][col] > a[max_r][i]) max_r = i; if(max_r != k) for(int i = col; i < var+1; i++) swap(a[k][i], a[max_r][i]); if(a[k][col] == 0) { k--; free_rec[num++] = col; continue; } for(int i = k+1; i < equ; i++) if(a[i][col] != 0) for(int j = col; j < var+1; j++) a[i][j] ^= a[k][j]; } for(int i = k+1; i < equ; i++) if(a[i][col] != 0) return -1; if(var > k) return var - k; return 0; } void solve(int S) { int state = (1<<S); int ans = INF; for(int i = 0; i < state; i++) { int cnt = 0; for(int j = 0; j < S; j++) { if((1<<j) & i) { cnt++; x[free_rec[j]] = 1; } else x[free_rec[j]] = 0; } for(int j = var-S-1; j >= 0; j--) { int temp = a[j][var]; for(int l = j+1; l < var; l++) if(a[j][l]) temp ^= x[l]; x[j] = temp; cnt += x[j] ? 1 : 0; } ans = min(ans, cnt); } printf("%d\n", ans); } int main() { while(scanf("%d", &a[0][20]) != EOF) { a[0][0] = 1, a[0][1] = 1, a[0][20] ^= 0; init_a(); solve(Gauss()); } return 0; }