POJ 1222 EXTENDED LIGHTS OUT (高斯消元)
题意:5*6矩阵中有30个灯,操作一个灯,周围的上下左右四个灯会发生相应变化 即由灭变亮,由亮变灭,如何操作使灯全灭?
题解:这个问题是很经典的高斯消元问题。同一个按钮最多只能被按一次,因为按两次跟没有按是一样的效果。那么 对于每一个灯,用1表示按,0表示没有按,那么每个灯的状态的取值只能是0或1。列出30个方程,30个变元,高斯消元解出即可。打表观察我们可以发现5*6的矩阵是一定有解的,主对角线元素都是1所以一定有唯一解。
打表代码:
#include <iostream> #include <cmath> #include <cstring> #include <cstdio> using namespace std; char s[300][300]; int g[300][300],ans[300];//注意这里定义的大小是n^2 不是n int dir[5][2]= {{0,0},{0,1},{0,-1},{1,0},{-1,0}}; int n,m1,m2; int gauss() { int row,col; for(row=0,col=0; row<n&&col<n; col++) //注意是小于n { int id=row; for(int i=row+1; i<n; i++) if(g[i][col]) id=i; if(g[id][col]) { for(int k=col; k<=n; k++) swap(g[id][k],g[row][k]);//注意这里是k for(int j=row+1; j<n; j++) if(g[j][col]) for(int k=col; k<=n; k++) //注意这里每段代码的特点 一点都不能写错 g[j][k]^=g[row][k]; row++;//一定注意这句话放到if里 } } for(int i=0;i<n;i++) { for(int j=0;j<n;j++) printf("%d ",g[i][j]); printf(" *******\n"); } // for(int i=row; i<n; i++) // if(g[i][n]) return -1; // int ans=0; // for(int i=n-1; i>=0; i--) // { // for(int j=n-1; j>i; j--) // g[i][n]^=g[i][j]&&g[j][n]; // ans+=g[i][n]; // } // return ans; return -1; } int main() { m1=5;m2=6; n=m1*m2; //1 memset(g,0,sizeof(g)); for(int i=0; i<m1; i++) for(int j=0; j<m2; j++) for(int k=0; k<5; k++) { int a=i+dir[k][0]; int b=j+dir[k][1]; if(a>=0&&b>=0&&a<m1&&b<m2) g[a*m2+b][i*m2+j]=1; //注意这里是 *m2, 模拟几个数就能理解了 } int ans1,ans2; ans1=gauss(); return 0; }
AC代码:
#include <iostream> #include <cmath> #include <cstring> #include <cstdio> using namespace std; int n=30; int f[35][35]; int g[35][35]; int dir[5][2]= {{0,0},{0,1},{1,0},{-1,0},{0,-1}}; void input() { for(int i=0; i<30; i++) scanf("%d",&g[i][30]); } void work() { int row,col; for(row=0,col=0; row<n&&col<n; col++) { int id=row; for(int i=id; i<n; i++) if(g[i][col]) id=i; if(g[id][col]) { for(int k=col; k<=n; k++) swap(g[row][k],g[id][k]); for(int i=row+1; i<n; i++) if(g[i][col]) for(int k=col; k<=n; k++) g[i][k]^=g[row][k]; row++; } } //构建上三角完毕 下面开始回代过程 for(int i=n-1;i>=0;i--) for(int j=n-1;j>i;j--) g[i][30]^=g[i][j]&&g[j][30]; //这一行可以参考传统的求解过程来理解 } void print() { for(int i=0; i<30; i++) { if((i+1)%6!=0) printf("%d ",g[i][30]); else printf("%d\n",g[i][30]); } } void debug() { for (int i =0; i <30; i++) { for (int j =0; j <31; j++) cout <<""<< g[i][j]; cout << endl; } cout << endl; } int main() { for(int i=0; i<5; i++) for(int j=0; j<6; j++) for(int k=0; k<5; k++) { int a=i+dir[k][0]; int b=j+dir[k][1]; if(a>=0&&b>=0&&a<5&&b<6) f[i*6+j][a*6+b]=1; } int t,cas=1; scanf("%d",&t); while(t--) { printf("PUZZLE #%d\n",cas++); memcpy(g,f,sizeof(g)); input(); work(); print(); } return 0; }