【poj1830-开关问题】高斯消元求解异或方程组

第一道高斯消元题目~

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

 

我们用样例来模拟一下:

【poj1830-开关问题】高斯消元求解异或方程组

我的高斯消元求解异或方程组模版:

 

 1 int gauss()
 2 {
 3     int i,j,k,l;
 4     //j=当前要消第几个元
 5     //i=当前消了几个元+1(n-i+1就是*元个数),也就是当前j要处理的这个方程将要放在第i行,构成上三角矩阵。
 6     //i、j不等是因为有些元是*元,不需要消,这些方程放到最后面(维护上三角矩阵)。
 7     for(i=1,j=1;i<=n && j<=n;j++)
 8     {
 9         for(k=j;k<=n;k++) 
10             if(a[k][j]) break;//先找到一个这个元的系数不为0方程的换到第i行。
11         if(a[k][j])
12         {
13             for(l=1;l<=n+1;l++) swap(a[i][l],a[k][l]);
14             for(l=1;l<=n;l++)//注意这里从1开始,因为把最后回代的过程合并了
15             {
16                 if(l!=i && a[l][j])//如果系数不为0才异或消元
17                     for(k=1;k<=n+1;k++) 
18                         a[l][k]^=a[i][k];
19             }
20             i++;
21         }
22     }        
23     for(j=i;j<=n;j++)
24         if(a[j][n+1]) return -1;
25     return 1<<(n-i+1);
26 }

 

 

 

 

说一下解的个数问题:

对增广矩阵[A b]做初等行变换,化成阶梯形(高斯消元法),如果存在[0,0,…,0,1]的行,就是无解;如果存在r行[0,0,…,0,0],就意味着有r个*变量,因为这里的变量只取0/1,所以有2r个解;如果不存在[0,0,…,0,*],即把最后一行去掉后不存在全0行,则A为满秩矩阵,则方程组有唯一解。

 

代码:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<algorithm>
 7 using namespace std;
 8 
 9 const int N=35;
10 int n,bit[N],a[N][N];
11 
12 void output()
13 {
14     for(int i=1;i<=n;i++)
15     {
16         for(int j=1;j<=n+1;j++) 
17             printf("%d ",a[i][j]);
18         printf("
");
19     }
20     printf("
");
21 }
22 
23 int gauss()
24 {
25     int i,j,k,l;
26     //j=当前要消第几个元
27     //i=当前消了几个元+1(n-i+1就是*元个数),也就是当前j要处理的这个方程将要放在第i行,构成上三角矩阵。
28     //i、j不等是因为有些元是*元,不需要消,这些方程放到最后面(维护上三角矩阵)。
29     for(i=1,j=1;i<=n && j<=n;j++)
30     {
31         for(k=j;k<=n;k++) 
32             if(a[k][j]) break;//先找到一个这个元的系数不为0方程的换到第i行。
33         if(a[k][j])
34         {
35             for(l=1;l<=n+1;l++) swap(a[i][l],a[k][l]);
36             for(l=1;l<=n;l++)//注意这里从1开始,因为把最后回代的过程合并了
37             {
38                 if(l!=i && a[l][j])//如果系数不为0才异或消元
39                     for(k=1;k<=n+1;k++) 
40                         a[l][k]^=a[i][k];
41             }
42             i++;
43         }
44     }        
45     for(j=i;j<=n;j++)
46         if(a[j][n+1]) return -1;
47     return 1<<(n-i+1);
48 }
49 
50 int main()
51 {
52     int T,x,y;
53     scanf("%d",&T);
54     while(T--)
55     {
56         scanf("%d",&n);
57         memset(a,0,sizeof(a));
58         for(int i=1;i<=n;i++) scanf("%d",&a[i][n+1]);
59         for(int i=1;i<=n;i++)
60         {
61             scanf("%d",&x);
62             a[i][n+1]^=x;
63         }
64         while(1)
65         {
66             scanf("%d%d",&x,&y);
67             if(!x && !y) break;
68             a[y][x]=1;
69         }
70         for(int i=1;i<=n;i++) a[i][i]=1;
71         int ans=gauss();
72         if(ans==-1) printf("Oh,it's impossible~!!
");
73         else printf("%d
",ans);
74     }
75     return 0;
76 }