poj3279Fliptile

poj3279Fliptile

题目大意及理解

大意就是心情愉悦能让奶牛产更多的奶,所以农民搞了个游戏给奶牛玩,奶牛
需要把所有黑色朝上的格子变成白色(1代表黑色,0代表白色),因为奶牛的
力气比较大,所以在翻动某一个格子时会同时翻转这个格子的邻接格子(上,下
左, 右)问怎样翻动可以使奶牛所需翻动次数最少,把每个格子的翻动次数以
矩阵的形式输出(只输出最少的)。如果全白时做不到的,输出IMPOSSIBLE

M-行数,N-列数
因为当第一行的翻动次数确定了,第一行的颜色也就确定了,所以第二行只需要
翻动本行格子上面的格子为黑色的格子,就能保证上一行全白。最后可以保证
M-1行全白,只需检验最后一行是否全白,就可以判断该种情况是否可行。
所以这到题目的重点是:
1.二进制枚举 第一行每个格子翻动状态只有翻或者不翻(可以想想为什么)
如果用0,1来表示,那么第一行所有的可能情况就是0 到 2^N所有数的二进制
表示。枚举所有情况即可。
2.搜索边界判断 可能这就是这道题目被归类到搜索题的原因。用搜索边界判
断的方法很好的解决了对于处在图不同地方的格子,对这些格子的颜色判断的
公式不同导致的繁琐。减少了代码的复杂性。

AC代码

# include <stdio.h>
# include <string.h>

int M, N;
int Map_f[20][20];
int Map_n[20][20];
int Map_ans[20][20];
int cnt = 0x3f3f3f3f;
int dir[5][2] = {
    -1,0,
    0,0,
    0,-1,
    1,0,
    0,1
};
int num;

int getcolor(int x, int y){
    int Count = 0;
    for(int i = 0; i < 5; i++)  {
        int xx = x + dir[i][0];
        int yy = y + dir[i][1];
        //搜索边界判断
        if(xx < 0 || yy < 0 || xx >= M || yy >= N)  continue;
        Count += Map_n[xx][yy];
    }
    Count += Map_f[x][y];
    if(Count%2)
        return true;
    else
        return false;
}

bool judge()    {
    num = 0;
    for(int i = 0; i < N; i++)  {
        if(Map_n[0][i] == 1)    num++;
    }
    for(int i = 1; i < M; i++)  {
        for(int j = 0; j < N; j++)  {
            if(getcolor(i-1,j)) {
                 Map_n[i][j] = 1;
                 num++;
            }
            else
                Map_n[i][j] = 0;
        }
    }
    for(int i = 0; i < N; i++)  {
        if(getcolor(M-1,i))
            return false;
    }
    return true;
}

int main()  {
    scanf("%d%d",&M,&N);
    for(int i = 0; i < M; i++)  {
        for(int j = 0; j < N; j++)  {
            scanf("%d",&Map_f[i][j]);
        }
    }
    /*for(int i = 0; i < M; i++)  {
        for(int j = 0; j < N; j++)  {
            printf("%d ",Map_f[i][j]);
        }
        printf("\n");
    }*/
    for(int k = 0; k < 1<<N; k++) {//二进制枚举。
        memset(Map_n,0,sizeof(Map_n));
        for(int i = 0; i < N; i++)  {
            Map_n[0][i] = k>>i&1;
            /*
				先把需要比较的某位数字移动到个位,再和1进行按位与计算
				能保证,结果为0或者1
			*/
        }
        if(judge() && num < cnt) {
            for(int i = 0; i < M; i++)  {
                for(int j = 0; j < N; j++)  {
                    Map_ans[i][j] = Map_n[i][j];
                }
            }
            cnt = num;
        }
    }
    if(cnt == 0x3f3f3f3f)
        printf("IMPOSSIBLE\n");
    else    {
        for(int i = 0; i < M; i++)  {
            for(int j = 0; j < N; j++)  {
                printf("%d",Map_ans[i][j]);
                if(j != N-1)
                    printf(" ");
            }
            printf("\n");
        }
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值