POJ 3279 Fliptile(反转)

来源:互联网 发布:pixiv软件怎么注册 编辑:程序博客网 时间:2024/06/05 12:18

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 16const 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;}
0 0
原创粉丝点击