POJ1222 EXTENDED LIGHTS OUT 高斯消元入门

来源:互联网 发布:mac用户文件夹在哪里 编辑:程序博客网 时间:2024/05/21 17:51

题目链接:POJ1222

参考来源:大佬的题解

关于这个知识点我翻了许多博客,最后找到这一篇讲的十分清楚,所以转在这里。部分代码加了自己的注释,方便大家更容易看明白。

题意:给出一个5*6的图,每个灯泡有一个初始状态,1表示亮,0表示灭。每对一个灯泡操作时,会影响周围的灯泡改变亮灭,问如何操作可以使得所有灯泡都关掉。

思路:因为每盏灯,如果操作两次就相当于没有操作,所以相当于(操作次数)%2,即异或操作。

考虑一个2*3的图,最后需要的状态是 :,如果初始状态为:。对这两个矩阵的每个数字做异或操作可以得到线性方程组每个方程的答案。

总共6盏灯,0-5。那么可以列出6个方程。

对于第0盏灯,会影响到它的是第0, 1, 3盏灯,因此可以列出方程1*x0 + 1*x1 + 0*x2 + 1*x3 + 0*x4 + 0*x5= 0。

对于第1盏灯,会影响到它的是第0, 1, 2,4盏灯,因此可以列出方程1*x0 + 1*x1 + 1*x2 + 0*x3 + 1*x4 + 0*x5 = 1。

对于第2盏灯,会影响到它的是第1, 2, 5盏灯,因此可以列出方程0*x0 + 1*x1 + 1*x2 + 0*x3 + 0*x4 + 1*x5 = 0。

.....

所以最后可以列出增广矩阵:

然后用高斯消元求这个矩阵的解就可以了。

AC代码:

/*2017年8月18日21:35:13POJ1222高斯消元解异或方程组模板AC */#include <iostream>#include <map>#include <set>#include <string>#include <cstring>#include <cstdio>#include <algorithm>#include <cmath>#include <queue>using namespace std;const int maxn=8;int a[maxn*maxn][maxn*maxn];int x[maxn*maxn];int mp[maxn][maxn];void init(){memset(a,0,sizeof(a));for(int i=0;i<5;i++){for(int j=0;j<6;j++){int pos=i*6+j;a[pos][pos]=1;//当前位置 if(j>0) a[pos][i*6+j-1]=1;//当前位置的左边 if(j<5) a[pos][i*6+j+1]=1;//当前位置的右边 if(i>0) a[pos][(i-1)*6+j]=1;//当前位置的上边 if(i<4) a[pos][(i+1)*6+j]=1;//当前位置的下边 }}}void Gauss(int n,int m){memset(x,0,sizeof(x));int r,c;for(r=0,c=0;r<n&&c<m;r++,c++){int max_r=r;for(int i=r+1;i<n;i++){if(fabs(a[i][c])>fabs(a[max_r][c]))max_r=i;}if(a[max_r][c]==0){r--;continue;//处理当前行的下一个位置,或者说下一列 }if(max_r!=r){//交换这两行从第C列开始的元素,包括第m行 for(int i=c;i<m+1;i++) swap(a[max_r][i],a[r][i]);}for(int i=r+1;i<n;i++){if(a[i][c]==0) continue;//如果该行第一个元素的值为0,跳过for(int j=c;j<m+1;j++) a[i][j]=a[i][j]^a[r][j]; } }for(int i=m-1;i>=0;i--){x[i]=a[i][m];for(int j=i+1;j<m;j++){x[i]=x[i]^(a[i][j]&&x[j]);}}} int main(){int t,kase=0;scanf("%d",&t);while(t--){init();for(int i=0;i<5;i++){for(int j=0;j<6;j++){scanf("%d",&a[i*6+j][30]);}}Gauss(30,30);printf("PUZZLE #%d\n",++kase);for(int i=0;i<5;i++){for(int j=0;j<6;j++){if(!j) printf("%d",x[i*6+j]);else printf(" %d",x[i*6+j]);}printf("\n");}}return 0;}



原创粉丝点击