第一道高斯消元题目~
题目:有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=i+1;l<=n;l++) 15 { 16 if(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("\n"); 19 } 20 printf("\n"); 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=j+1;l<=n;l++) 37 { 38 if(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~!!\n"); 73 else printf("%d\n",ans); 74 } 75 return 0; 76 }
时间: 2024-08-10 02:58:21