POJ 3279 Fliptile

原题链结

恩...与白书上的思路一样 

枚举第0行翻转的所有情况 然后依次向下更新 

如果上一行为1,这一行肯定需要翻转,直到更新完(m-2)行

再检索一遍(m-1)行  如果(m-1)行都为0 这种情况符合题意 更新翻转的最少次数 记录下最优解

话不多说 上代码


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<string>
#include<stack>
#include<queue>
#include<cmath>
#include<stack>
#include<list>
#include<map>
typedef long long ll;
using namespace std;
int m,n;
int tile[17][17],most[17][17],flip[17][17]; //tile是初始地图 most记录最优解 flip记录中间结果

int nextx[5]={0,1,0,-1,0};
int nexty[5]={1,0,-1,0,0};  //翻转一个格子,其实要翻转五个格子

int get(int x,int y)
{
    int c=tile[x][y];  // 初始时 坐标为(x,y)的格子的状态
    for(int k=0;k<5;k++)
    {
        int tx=x+nextx[k],ty=y+nexty[k]; //更新到邻接格子
        if(tx>=0&&tx<m&&ty>=0&&ty<n)
        {
            c+=flip[tx][ty];   //在初始状态的基础上加上翻转次数
        }
    }
    return c%2;//如果为奇数 那么这个格子现在状态为1 也就是黑色
}

int cal()
{
    int i,k,j;
    for(i=1;i<m;i++)
    {
        for(j=0;j<n;j++)
        {
            if(get(i-1,j)!=0) //上一行格子是1,说明这一行需要翻转
            {
                flip[i][j]=1;  //这个地方不要把邻接的格子都更新,在get函数里已经更新了!
            }
        }
    }
    for(j=0;j<n;j++)
    {
        if(get(m-1,j)!=0)return -1; //检索最后一行 是否全部为0
    }
    int res=0;
    for(i=0;i<m;i++)
    {
        for(j=0;j<n;j++)
        {
            res+=flip[i][j];  //计算出总的翻转次数
        }
    }
    return res;
}


int main()
{
    int i,j,k;
    while(scanf("%d%d",&m,&n)==2)
    {
           int cnt=0;
            for(i=0;i<m;i++)
            for(j=0;j<n;j++)
            {
                scanf("%d",&tile[i][j]);
                cnt+=tile[i][j];
            }
            if(cnt==0)
            {
                printf("0\n"); //全部为0 无需翻转
                continue;
            }

        int ans=0xfffffff;
        for(i=0;i< 1<<n;i++)
        {
            memset(flip,0,sizeof(flip));//不要忘记初始化,在这个地方WA了几次...开始时翻转次数都为0
            for(j=0;j<n;j++)
            {
                flip[0][n-j-1]=i>>j&1;  //枚举第一行的翻转情况
            }
            int num=cal();
            if(num>=0)
            {

                 if(ans>num)
                 {
                    ans=num;
                    memcpy(most,flip,sizeof(flip));//更新res ,并保存最优解
                 }

            }

        }
        if(ans==0xfffffff)
        {
            printf("IMPOSSIBLE\n");
        }
        else{
          for(i=0;i<m;i++)
          {

              for(j=0;j<n;j++)
              {
                 printf("%d%c",most[i][j],j+1==n?'\n':' ');
              }
          }
        }

    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值