[POJ1830]开关问题(高斯消元,异或方程组)
题目链接:http://poj.org/problem?id=1830
题意:中文题面,求的是方案数。
首先可以知道, 如果方案数不止一个的话,说明矩阵行列式值为0,即存在自由变元,由于变量只有两种状态,那么方案数就是2^自由变元数。
从起始状态到终止状态,只需要关心起始和终止哪些状态不一样就行,也就是翻转奇数次。
由于是倒推,所以开关的影响要反过来存。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 const int maxn = 33; 6 int equ, var; 7 int a[maxn][maxn]; 8 int x[maxn]; 9 int free_x[maxn]; 10 int free_num; 11 12 int gauss() { 13 int max_r, col, k; 14 free_num = 0; 15 for(k = 0, col = 0; k < equ && col < var; k++, col++) { 16 max_r = k; 17 for(int i = k + 1; i < equ; i++) { 18 if(abs(a[i][col]) > abs(a[max_r][col])) 19 max_r = i; 20 } 21 if(a[max_r][col] == 0) { 22 k--; 23 free_x[free_num++] = col; 24 continue; 25 } 26 if(max_r != k) { 27 for(int j = col; j < var + 1; j++) 28 swap(a[k][j], a[max_r][j]); 29 } 30 for(int i = k + 1; i < equ; i++) { 31 if(a[i][col] != 0) { 32 for(int j = col; j < var + 1; j++) { 33 a[i][j] ^= a[k][j]; 34 } 35 } 36 } 37 } 38 for(int i = k; i < equ; i++) { 39 if(a[i][col] != 0) 40 return -1; 41 } 42 if(k < var) return var - k; 43 for(int i = var - 1; i >= 0; i--) { 44 x[i] = a[i][var]; 45 for(int j = i + 1; j < var; j++) { 46 x[i] ^= (a[i][j] & x[j]); 47 } 48 } 49 return 0; 50 } 51 52 int main() { 53 // freopen("in", "r", stdin); 54 int T, _ = 1; 55 char wtf[66] = "Oh,it's impossible~!!"; 56 scanf("%d", &T); 57 while(T--) { 58 scanf("%d", &var); 59 equ = var; 60 memset(a, 0, sizeof(a)); 61 memset(x, 0, sizeof(x)); 62 memset(free_x, 0, sizeof(free_x)); 63 for(int i = 0; i < var; i++) { 64 scanf("%d", &a[i][var]); 65 a[i][i] = 1; 66 } 67 int u, v; 68 for(int i = 0; i < var; i++) { 69 scanf("%d", &u); 70 a[i][var] ^= u; 71 } 72 while(~scanf("%d%d",&u,&v) && u+v) { 73 a[v-1][u-1] = 1; 74 } 75 int ret = gauss(); 76 if(ret == -1) puts(wtf); 77 else printf("%lld\n", (LL)((LL)1 << ret)); 78 } 79 return 0; 80 }