標籤:style blog http color os io 資料 for
題目連結
題意:給定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 }