poj 1830 开关问题 (高斯消元)
题意:给定N(N < 29)个开关,每个开关打开和关闭的时候会引起另外一个开关的变化,本来为打开的会变成关闭,
本来关闭的会变成打开。给定N个开关的初始状态和终止状态,以及关联的开关关系,求共有多少种方案从初始状态变成终止状态(不计顺序,并且每个开关只能操作至多一次)。
分析:
由于开关只有打开和关闭两种状态,所以对于每个开关的打开和关闭,组合一下总共有2^N种情况,枚举所有情况判可行性,对于这个数据量来说是不现实的,需要想办法优化。
start + x(i) * A(i) = end
x(i) * A(i) = start ^ end 即当开始状态和结束状态不同的时候才取1 来改变状态。。
系数矩阵A[i][j]代表了开关之间的连带关系:
1) 如果第j个开关的操作能够影响第i个开关的状态,那么A[i][j] = 1;
2) 如果第j个开关的操作不影响第i个开关的状态,那么A[i][j] = 0;
3) 特殊的A[i][i] = 1(开关本身的操作必然会影响自己的当前状态);
但是还是不理解为什么不是前面 影响 后面????
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <algorithm> 7 #define LL __int64 8 const int maxn = 30+10; 9 using namespace std; 10 int equ, var, fn; 11 int a[maxn][maxn], x[maxn]; 12 13 int gcd(int a, int b) 14 { 15 return b==0?a:gcd(b, a%b); 16 } 17 int lcm(int a, int b) 18 { 19 return a*b/gcd(a, b); 20 } 21 int Gauss() 22 { 23 int x_mo; 24 x_mo = 2; 25 int i, j, k, max_r, col; 26 int ta, tb, LCM; 27 col = 0; 28 29 for(k = 0; k<equ && col<var; k++, col++) 30 { 31 max_r = k; 32 for(i = k+1; i < equ; i++) 33 if(abs(a[i][col])>abs(a[max_r][col])) 34 max_r = i; 35 36 if(max_r != k) 37 for(j = k; j < var+1; j++) 38 swap(a[k][j], a[max_r][j]); 39 40 if(a[k][col]==0) 41 { 42 k--; 43 continue; 44 } 45 for(i = k+1; i < equ; i++) 46 { 47 if(a[i][col] != 0) 48 { 49 LCM = lcm(abs(a[i][col]), abs(a[k][col])); 50 ta = LCM/abs(a[i][col]); 51 tb= LCM/abs(a[k][col]); 52 if(a[i][col]*a[k][col] < 0) tb = -tb; 53 54 for(j = col; j < var+1; j++) 55 a[i][j] = ((a[i][j]*ta - a[k][j]*tb)%x_mo+x_mo)%x_mo; 56 } 57 } 58 } 59 for(i = k; i < equ; i++) 60 if(a[i][col] != 0) 61 return -1; 62 63 if(k < var) 64 return var-k; 65 return 0; 66 } 67 int main() 68 { 69 int i, t, n; 70 int b[maxn], e[maxn], c, d; 71 scanf("%d", &t); 72 while(t--) 73 { 74 cin>>n; 75 equ = n; 76 var = n; 77 memset(a, 0, sizeof(a)); 78 for(i = 0; i < n; i++) 79 cin>>b[i]; 80 for(i = 0; i < n; i++) 81 cin>>e[i]; 82 while(cin>>c>>d) 83 { 84 if(c==0 && d==0) break; 85 a[d-1][c-1] = 1; //注意题目里是从1开始的,注意是c在后,后面影响前面。但是还是不理解为什么 86 } 87 for(i = 0; i < n; i++) 88 a[i][i] = 1; 89 for(i = 0; i < n; i++) 90 a[i][n] = (b[i]^e[i]); //当开始状态和结束状态不同的时候才取1 来改变状态 91 fn = Gauss(); 92 if(fn==-1) 93 printf("Oh,it's impossible~!!\n"); 94 else 95 { 96 fn = (1<<fn); //因为有fn个变元,而有0,1两种状态,所以情况数是2^fn。 97 cout<<fn<<endl; 98 } 99 } 100 return 0; 101 }