您的位置:首页 > 其它

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

2017-07-06 17:47 288 查看




题意:给出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;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: