poj 1222 (枚举or高斯消元)

xiaoxiao2021-02-28  16

传送门:点击打开链接

题意:给你一个5*6的矩阵,每个点上都有一个灯,按下f[i][j]的按钮,f[i][j]位置的灯的状态会改变,它上下左右的灯的状态也会改变(开变关,关变开)。现在给出这个矩阵的初始状态,输出按下哪些按钮,使所有的灯都关闭。

 

分析:

解法一(穷举法):我们可以先二进制枚举第一行所有的翻转情况,才64种。之后第一行已经确定了,然后看第2行,如果第一行某个位置为1,那么在同一列的第2行这个位置必须反转。。(因为第一行已经确定,不能再反转了,而影响第一行的,也只有在同一列的第2行),这样我们可以确定了,前N-1行,全部为0,最后单独检查最后一行,是否全部为0。

解法二(高斯消元):每个位置可以列出一个方程, 列出增广矩阵: 每个位置可以形成增广矩阵的一行, 每行都有30个系数 分别代表(0到29号灯), 将 可以影响该位置改变的 位置(自己、上、下、左、右)对应的置1, 其余置0,这样就形成了30*30的系数矩阵。将初始状态置入最后一列,就形成了增广矩阵。这里是解亦或方程组,注意与解普通方程组的区别,把加减改成亦或,乘法改成&&,代码参考大牛写的。。。

代码:

#include<iostream> #include<cmath> #include<cstdio> #include<cstring> using namespace std; int n,mp[10][10],tp[10][10],b[10][10]; int gb(int x,int y) { int s=b[x][y]; if(x>0) s+=b[x-1][y]; if(y>0) s+=b[x][y-1]; if(y<5) s+=b[x][y+1]; return s; } void sv() { for(int i=0;i<(1<<6);i++) { memset(tp,0,sizeof(tp)); for(int j=0;j<6;j++) { if( i&(1<<(5-j)) ) b[0][j]=1; else b[0][j]=0; } for(int j=0;j<6;j++) { int s=b[0][j]; if(j>0) s+=b[0][j-1]; if(j<5) s+=b[0][j+1]; if(s%2) tp[0][j]=1^mp[0][j]; else tp[0][j]=mp[0][j]; } for(int j=1;j<5;j++) { for(int k=0;k<6;k++) { if(tp[j-1][k]) b[j][k]=1; else b[j][k]=0; } for(int k=0;k<6;k++) { int sum=gb(j,k); if(sum%2) tp[j][k]=1^mp[j][k]; else tp[j][k]=mp[j][k]; } } int s=0; for(int j=0;j<6;j++) s+=tp[4][j]; if( s==0 ) { for(int j=0;j<5;j++){ for(int k=0;k<6;k++) { cout<<b[j][k]; if( k!=5 ) cout<<" "; } cout<<endl; } } } } int main() { cin>>n; for(int t=1;t<=n;t++) { for(int i=0;i<5;i++) for(int j=0;j<6;j++) cin>>mp[i][j]; cout<<"PUZZLE #"<<t<<endl; sv(); } return 0; }

 

#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; int a[300][300]; /// 增广矩阵 int x[300]; /// 解 int free_x[300]; /// 标记是否为自由未知量 int n, m; void Gauss(int n, int m) /// n个方程 m个未知数 即 n行m+1列 { ///转换为阶梯形式 int col=0, k, num=0; for(k=0;k<n && col<m;k++, col++) {///枚举行 int max_r=k; for(int i=k+1;i<n;i++)///找到第col列元素绝对值最大的那行与第k行交换 if(abs(a[i][col])>abs(a[max_r][col])) max_r=i; for(int j=col;j<m+1;j++)/// 与第k行交换 swap(a[k][j], a[max_r][j]); /* if(!a[k][col])// 说明该col列第k行以下全是0了 { k--; free_x[num++]=col; continue; } */ for(int i=k+1;i<n;i++)/// 枚举要删除的行 if(a[i][col]) for(int j=col;j<m+1;j++) a[i][j]^=a[k][j]; } /// 唯一解 回代 for(int i=m-1;i>=0;i--){ x[i]=a[i][m]; for(int j=i+1;j<m;j++) x[i]^=(a[i][j] && x[j]); } } void init(){ n=5, m=6; memset(a, 0, sizeof(a)); memset(x, 0, sizeof(x)); for(int i=0;i<n;i++) for(int j=0;j<m;j++){ int t=i*m+j; a[t][t]=1; if(i>0) a[(i-1)*m+j][t]=1; if(i<n-1) a[(i+1)*m+j][t]=1; if(j>0) a[i*m+j-1][t]=1; if(j<m-1) a[i*m+j+1][t]=1; } } int main(){ int t, ca=1; scanf("%d", &t); while(t--){ init(); for(int i=0;i<n*m;i++) scanf("%d", &a[i][n*m]); printf("PUZZLE #%d\n", ca++); Gauss(n*m, n*m); for(int i=0;i<n;i++) for(int j=0;j<m;j++){ printf("%d", x[i*m+j]); if(j==5) printf("\n"); else printf(" "); } } return 0; }

 

转载请注明原文地址: https://www.6miu.com/read-2650266.html

最新回复(0)