题意:有20个数字,0或1。如果改变一个数的状态,它左右两边的两个数的状态也会变反。问从目标状态到全0,至少需要多少次操作。
显然,问题可以从目标状态到全0 转化为 全0到目标状态。
于是可以列出方程组,每行一个数的状态。
为了知道操作次数,那么就要知道未知数为1有多少个,所以就要解方程组,解方程组就不得不枚举自由元了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define MAXN 20 5 #define MAXM 25 6 #define oo 0x7FFFFFFF 7 using namespace std; 8 int g[MAXM][MAXM], tmp[MAXM], x[MAXM]; 9 int ans; 10 bool Read() { 11 int i; 12 for (i = 0; i < MAXN; i++) { 13 if (scanf("%d", &g[i][MAXN]) == EOF) 14 return false; 15 } 16 return true; 17 } 18 int Cal() { 19 int i, j, k, cnt; 20 k = cnt = 0; 21 for (i = MAXN - 1; i >= 0; i--) { 22 if (g[i][i]) { 23 x[i] = g[i][MAXN]; 24 for (j = i + 1; j < MAXN; j++) 25 x[i] ^= x[j] && g[i][j]; 26 } else 27 x[i] = tmp[k++]; 28 if (x[i]) 29 cnt++; 30 } 31 return cnt; 32 } 33 void DFS(int now, int cnt) { 34 if (cnt == 0) 35 ans = min(ans, Cal()); 36 else { 37 tmp[now] = 0; 38 DFS(now + 1, cnt - 1); 39 tmp[now] = 1; 40 DFS(now + 1, cnt - 1); 41 } 42 } 43 void Gauss() { 44 int r, c, i, j; 45 for (c = r = 0; c < MAXN; c++, r++) { 46 for (i = r; i < MAXN; i++) { 47 if (g[i][c]) 48 break; 49 } 50 if (i >= MAXN) 51 r--; 52 else { 53 if (i != r) { 54 for (j = 0; j <= MAXN; j++) 55 swap(g[i][j], g[r][j]); 56 } 57 for (i = r + 1; i < MAXN; i++) { 58 if (g[i][c]) { 59 for (j = c; j <= MAXN; j++) 60 g[i][j] ^= g[r][j]; 61 } 62 } 63 } 64 } 65 DFS(0, MAXN - r); 66 } 67 int main() { 68 int i; 69 while (Read()) { 70 for (i = 0; i < MAXN; i++) { 71 g[max(i - 1, 0)][i] = 1; 72 g[i][i] = 1; 73 g[min(MAXN - 1, i + 1)][i] = 1; 74 } 75 ans = oo; 76 Gauss(); 77 printf("%d\n", ans); 78 } 79 return 0; 80 }