第一道高斯消元题目~
题目:有N个相同的开关,每个开关都与某些开关有着联系,每当你打开或者关闭某个开关的时候,其他的与此开关相关联的开关也会相应地发生变化,即这些相联系的开关的状态如果原来为开就变为关,如果为关就变为开。你的目标是经过若干次开关操作后使得最后N个开关达到一个特定的状态。对于任意一个开关,最多只能进行一次开关操作。你的任务是,计算有多少种可以达到指定状态的方法。(不计开关操作的顺序)0<=N<=29
我们用样例来模拟一下:
我的高斯消元求解异或方程组模版:
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 }