您的位置:首页 > 其它

POJ 3279 Fliptile(反转)

2015-08-30 08:41 477 查看
Description

一个m*n的格子,每个格子可以反转正反面,一面黑一面白,农夫约翰的牛现在玩游戏,把所有格子都反转成白色,因牛蹄很大,每次反转一个格子会让其上下左右相邻接的格子也反转。现在给定格子颜色,求最少操作次数完成该游戏,如果不能完成则输出IMPOSSIBLE

Input

第一行两个整数m和n表示格子的行列数,之后一个m*n矩阵表示格子颜色,0表示白色,1表示黑色

Output

如能完成游戏则输出最少步数,如果不能则输出IMPOSSIBLE

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

Solution

因为最后格子状态只能为全黑或全白,以将格子变成全黑为例,首先枚举第一行的反转情况,然后一行行向下递推,后面格子的反转必须使得前一行格子变成黑色,这样一来当将第四行反转完后前三行都为黑色,这时只需判断第四行是否全黑即可,对于每次满足条件的枚举枚举更新最小反转次数

Code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
#define maxn 16
const int dx[5]={-1,0,0,0,1};//邻接格子坐标
const int dy[5]={0,-1,0,1,0};
int m,n;
int map[maxn][maxn];//格子初始状态
int ans[maxn][maxn];//保存最优解
int temp[maxn][maxn];//保存中间结果
int get(int x,int y)//查询(x,y)的颜色
{
int c=map[x][y];
for(int i=0;i<5;i++)
{
int xx=x+dx[i],yy=y+dy[i];
if(xx>=0&&xx<m&&yy>=0&&yy<n)
c+=temp[xx][yy];
}
return c%2;
}
int solve()//求出第一行确定情况下的最少操作次数,不存在返回-1
{
for(int i=1;i<m;i++)
for(int j=0;j<n;j++)
if(get(i-1,j)!=0)//(i-1,j)是黑色,则必须反转此格子
temp[i][j]=1;
for(int j=0;j<n;j++)//判断最后一行是否为全白
if(get(m-1,j)!=0)//无解
return -1;
int res=0;
for(int i=0;i<m;i++)//统计反转次数
for(int j=0;j<n;j++)
res+=temp[i][j];
return res;
}
int main()
{
scanf("%d%d",&m,&n);
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
scanf("%d",&map[i][j]);
int res=-1;
for(int i=0;i<1<<n;i++)//按照字典序尝试第一行所有可能性
{
memset(temp,0,sizeof(temp));//初始化
for(int j=0;j<n;j++)
temp[0][n-1-j]=i>>j&1;
int num=solve();
if(num>=0&&(res<0||res>num))
{
res=num;//更新最少操作次数
memcpy(ans,temp,sizeof(temp));//复制最优解
}
}
if(res<0)//无解
printf("IMPOSSIBLE\n");
else
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
printf("%d%c",ans[i][j],j==n-1?'\n':' ');
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: