题目描述:
多组数据,每次给出一个$5*6$的$01$矩阵,代表灯暗、灯亮。
你要关灯但是按下一个灯会影响上下左右。
求方案。
题解:
显然不可能按同一个灯泡两次。
高消搞一下。
代码:
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int t,nam[10][10],a[35][35],ans[35]; int dx[5]={-1,1,0,0,0},dy[5]={0,0,1,-1,0}; void init() { int tot = 0; for(int i=1;i<=5;i++) for(int j=1;j<=6;j++) nam[i][j]=++tot; } bool check(int x,int y) { return x>=1&&x<=5&&y>=1&&y<=6; } int fre[35],tl; int gs() { int l1,l2; tl=0; for(l1=l2=1;l1<=30&&l2<=30;l1++,l2++) { int tmp = l1; for(int j=l1;j<=30;j++) if(abs(a[j][l2])>abs(a[tmp][l2]))tmp=j; if(tmp!=l1) for(int j=l2;j<=31;j++)swap(a[l1][j],a[tmp][j]); if(!a[l1][l2]) { fre[++tl]=l2; l1--; continue; } for(int j=l1+1;j<=30;j++) if(a[j][l2]) for(int k=l2;k<=31;k++) a[j][k]^=a[l1][k]; } for(int i=l1+1;i<=30;i++) if(a[i][31])return -1; if(l1<30)return 30-l1; for(int i=30;i>=1;i--) { ans[i]=a[i][31]; for(int j=i-1;j>=1;j--) a[j][31]^=(a[i][31]&a[j][i]); } } int main() { scanf("%d",&t);int tim=0; init(); while(t--) { memset(a,0,sizeof(a)); printf("PUZZLE #%d ",++tim); for(int c,i=1;i<=5;i++) for(int j=1;j<=6;j++) { scanf("%d",&c);int u = nam[i][j]; for(int x,y,k=0;k<5;k++) { x = i+dx[k],y = j+dy[k]; if(!check(x,y))continue; a[u][nam[x][y]]=1; } a[u][31]=c; } int k = gs(); int u = 0; for(int i=1;i<=5;i++,puts("")) for(int j=1;j<=6;j++) { printf("%d ",ans[++u]); } } return 0; }