Fliptile
Time Limit: 2000MS | Memory Limit: 65536K |
Description
Input
Output
Sample Input
4 4 1 0 0 1 0 1 1 0 0 1 1 0 1 0 0 1
Sample Output
0 0 0 0 1 0 0 1 1 0 0 1 0 0 0 0
比较难想的一题,但是这也是很经典的一题 经典游戏“点亮灯泡”就是这种 也就是按下一个开关,这盏灯及上下左右的灯会改变状态 因为一个开关按两次是没有意义的 所以对于每个开关只有两种状态 按或者不按 所以这一题就是要求输出 每一个开关按(1)或者不按(0)
0000(0) 表示 否否否否 0001(1) 表示 否否否是 0010(2) 表示 否否是否 0011(3) 表示 否否是是以此类推即可用循环把所有操作表示出来 共有2m次循环 对于每一个i可以进行且操作i&1为二进制最后一位数 而对于判断灯亮灭则可使用异或操作 因为我们有运算法则
0^1==1 1^1==0 0^0==0 1^0==1也就是异或1则改变异或0则不变 这与灯是否被操作的情况是相同的 得到每种状态第一行的操作后 我们可以依次向下判断来更新答案
#include<stdio.h> #include<string.h> int map[20][20]; int temp[20][20]; int N,M; void Pr(int x) { for(int i=0; i<M; i++) { map[0][i] ^= (x>>(M-1-i))&1; if((x>>(M-1-i))&1) { if(i>0) map[0][i-1] ^= 1; if(i<M-1) map[0][i+1] ^= 1; if(N>1) map[1][i] ^= 1; } printf("%d",(x>>(M-1-i))&1); printf("%c",i==M-1?'\n':' '); } for(int i=1; i<N; i++) { for(int j=0; j<M; j++) { printf("%d",map[i-1][j]); if(map[i-1][j]==1) { map[i-1][j] ^= 1; map[i][j] ^= 1; if(j>0) map[i][j-1] ^= 1; if(j<M-1) map[i][j+1] ^= 1; if(i<N-1) map[i+1][j] ^= 1; } printf("%c",j==M-1?'\n':' '); } } } int main() { while(scanf("%d %d",&N,&M)!=EOF) { for(int i=0; i<N; i++) for(int j=0; j<M; j++) scanf("%d",&map[i][j]); int res=99999999,rest=-1; int T=(1<<M),max=T-1; while(T--) { memcpy(temp,map,sizeof(map)); int t=T^max; int cnt=0; for(int i=0; i<M; i++) { temp[0][i] ^= (t>>(M-1-i))&1; if((t>>(M-1-i))&1) { cnt++; if(i>0) temp[0][i-1] ^= 1; if(i<M-1) temp[0][i+1] ^= 1; if(N>1) temp[1][i] ^= 1; } } for(int i=1; i<N; i++) { for(int j=0; j<M; j++) { if(temp[i-1][j]==1) { cnt++; temp[i-1][j] ^= 1; temp[i][j] ^= 1; if(j>0) temp[i][j-1] ^= 1; if(j<M-1) temp[i][j+1] ^= 1; if(i<N-1) temp[i+1][j] ^= 1; } } } int i; for(i=0; i<M; i++) if(temp[N-1][i]==1) break; if(i==M&&cnt<res) res=cnt,rest=t; } if(res==99999999) printf("IMPOSSIBLE\n"); else Pr(rest); } return 0; }
题目地址:【POJ】[3279]Fliptile