POJ 3279 Fliptile (暴力枚举)(D)

来源:互联网 发布:南风知我意七微 编辑:程序博客网 时间:2024/06/06 01:50

题意:给出m行 n列 由0和1组成的矩阵  现在需要经他们全部翻转成0

翻转规则为:翻转的点和周围四个点同时翻转 即0变1 1变0

最后如果有多个解 输出次数最少的情况  如果翻转次数相同 则输出字典序最小的 

思路:翻转2次等于不翻 所有每个位置要么不翻要么不翻

如果第一行的翻转次数确定的话  那么剩下位置的翻转次数也唯一确定

第一行的所有情况为2^n次 枚举即可

#include<cstdio>#include<algorithm>#include<cstring>#include<iostream>#include<queue>#include<vector>using namespace std;#define maxn 25#define mem(vis,value) memset(vis,value,sizeof vis)int m,n;int maps[maxn][maxn];int num[maxn][maxn];int ans[maxn][maxn];int go[5][2]={0,0,0,1,0,-1,1,0,-1,0};int check(int x,int y)//判定点(x,y)这个点的状态是1还是0{int a=maps[x][y];//根据初始状态  他需要至少转几次 0则0次 1则1次int b=0;for(int i=0;i<5;i++){int fx=x+go[i][0];int fy=y+go[i][1];if(fx>=1&&fx<=m&&fy>=1&&fy<=n){b+=num[fx][fy];//这个点被翻了几次 旁边的被翻他也会被翻}}if((a+b)%2==0)return 0;//因为翻两次状态相当于不变else return 1;}int solve(){for(int i=2;i<=m;i++){for(int j=1;j<=n;j++){if(check(i-1,j)==1){num[i][j]=1;//当上一行的反转次数知道后  根据上一行的状态即可推断下一行的翻转次数}}}for(int i=1;i<=n;i++){if(check(m,i)==1)return -1;//即该情况不能全部翻成0}int  cnt=0;for(int i=1;i<=m;i++)for(int j=1;j<=n;j++)cnt+=num[i][j];//统计总共的翻转次数return cnt;}int main(){int t;while(~scanf("%d%d",&m,&n)){t=-1;for(int i=1;i<=m;i++){for(int j=1;j<=n;j++){scanf("%d",&maps[i][j]);}}for(int i=0;i<(1<<n);i++)//1<<n为枚举第一行所有的可能性{mem(num,0);for(int j=n;j>=1;j--){num[1][j]=(i>>(j-1))&1;//因为要求字典序小的优先输出 }int cnt=solve();if(cnt>0&&(t==-1||cnt<t)){t=cnt;memcpy(ans,num,sizeof num);}}if(t==-1)  printf("IMPOSSIBLE\n");else{for(int i = 1; i <= m; i++)for(int j = 1; j <= n; j++)printf("%d%c", ans[i][j], j == n ? '\n' : ' ');}}    return 0;}


原创粉丝点击