POJ 1830 高斯消元

开关问题
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 9883   Accepted: 3971

Description

有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。你的任务是,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)

Input

输入第一行有一个数K,表示以下有K组测试数据。 
每组测试数据的格式如下: 
第一行 一个数N(0 < N < 29) 
第二行 N个0或者1的数,表示开始时N个开关状态。 
第三行 N个0或者1的数,表示操作结束后N个开关的状态。 
接下来 每行两个数I J,表示如果操作第 I 个开关,第J个开关的状态也会变化。每组数据以 0 0 结束。 

Output

如果有可行方法,输出总数,否则输出“Oh,it's impossible~!!” 不包括引号

Sample Input

2
3
0 0 0
1 1 1
1 2
1 3
2 1
2 3
3 1
3 2
0 0
3
0 0 0
1 0 1
1 2
2 1
0 0

Sample Output

4
Oh,it's impossible~!!

 

思路:
高斯消元:a*X=b
若第x个开关跟第y个相连,则系数矩阵中a[y][x]=1,初始化中a[i][i]=1,初始情况和最后情况亦或一下就是我们的b矩阵。
 
代码:
 1 //#include"bits/stdc++.h"
 2 #include<sstream>
 3 #include<iomanip>
 4 #include"cstdio"
 5 #include"map"
 6 #include"set"
 7 #include"cmath"
 8 #include"queue"
 9 #include"vector"
10 #include"string"
11 #include"cstring"
12 #include"time.h"
13 #include"iostream"
14 #include"stdlib.h"
15 #include"algorithm"
16 #define db double
17 #define ll long long
18 #define vec vector<ll>
19 #define mt  vector<vec>
20 #define ci(x) scanf("%d",&x)
21 #define cd(x) scanf("%lf",&x)
22 #define cl(x) scanf("%lld",&x)
23 #define pi(x) printf("%d\n",x)
24 #define pd(x) printf("%f\n",x)
25 #define pl(x) printf("%lld\n",x)
26 //#define rep(i, x, y) for(int i=x;i<=y;i++)
27 #define rep(i, n) for(int i=0;i<n;i++)
28 const int N   = 1e2+ 5;
29 //const int mod = 1e9 + 7;
30 //const int MOD = mod - 1;
31 const int inf = 0x3f3f3f3f;
32 const db  PI  = acos(-1.0);
33 const db  eps = 1e-10;
34 using namespace std;
35 int equ,var;//equ个方程,var个变量,增广矩阵行数为equ,列数为var+1,分别为0到var
36 int a[N][N];//增广矩阵
37 int x[N];//存储自由变元
38 int f_x[N];
39 int free_x;//自由变元个数
40 void swap(int &x,int &y){
41     int t;
42     t=x,x=y,y=t;
43 }
44 int Gauss()
45 {
46     int ma_r,col,k;
47     free_x=0;
48     for(k=0,col=0;k<equ&&col<var;k++,col++){
49         ma_r = k;
50         for (int i = k + 1; i < equ; i++) if (abs(a[i][col] > abs(a[ma_r][col]))) ma_r = i;//取系数最大的一行
51         if (!a[ma_r][col]) {
52             k--;
53             f_x[free_x++] = col;
54             continue;
55         }
56         if (ma_r != k)
57             for (int j = col; j < var + 1; j++) swap(a[k][j], a[ma_r][j]);//与当前行交换
58 
59         for (int i = k + 1; i < equ; i++)
60             if (a[i][col] != 0)
61                 for (int j = col; j < var + 1; j++) a[i][j] ^= a[k][j];//消除其他行第col列的变量
62     }
63     for(int i=k;i<equ;i++) if(a[i][col]!=0) return -1;//没被消除则无解
64 
65     if(k<var) return var-k;//自由变元个数
66     //唯一解,回代
67     for(int i=var-1;i>=0;i--){
68         x[i]=a[i][var];
69         for(int j=i+1;j<var;j++) x[i]^=(a[i][j]&&x[j]);//自下而上
70     }
71     return 0;
72 }
73 int n;
74 int main()
75 {
76     int t;
77     ci(t);
78     for(int I=1;I<=t;I++){
79         memset(a,0,sizeof(a));
80         ci(n);
81         int x, y;
82         for (int i = 0; i < n; i++) ci(a[i][n]);
83         for (int i = 0; i < n; i++) ci(x), a[i][n] ^= x;
84         for (int i = 0; i < n; i++) a[i][i] = 1;
85         while (scanf("%d%d", &x, &y), x + y) a[y-1][x-1] = 1;
86         equ = n, var = n;
87         int ans = Gauss();
88         if(ans == -1) puts("Oh,it's impossible~!!");
89         else
90             pl(1ll << ans);
91     }
92     return 0;
93 }

 

 
posted @ 2018-04-23 00:25  thges  阅读(189)  评论(0编辑  收藏  举报