Poj1753 翻转棋子

这个题就是用枚举举遍所有情况,然后一个一个深搜看看是不是符合条件,符合条件直接退出,不符合则继续,

由于表格只有16个所以可以得知最多的步数只能是16,所以可以根据步数从0到16依次枚举,

第一个符合条件的就是最小的步数,为了容易深搜,可以设定顺序为一行一行深搜,当一行搜完时从下一行开头搜,

代码和测试数据如下:

#include<stdio.h>
int flag;
int step;
int map[4][4];

void turn(int i, int j) //转换
{
    map[i][j] = !(map[i][j]);
    if (i > 0)
    {
        map[i-1][j] = !(map[i-1][j]);
    }
    if (i < 3)
    {
        map[i + 1][j] = !(map[i + 1][j]);
    }
    if (j > 0)
    {
        map[i][j-1] = !(map[i][j-1]);
    }
    if (j < 3)
    {
        map[i][j + 1] = !(map[i][j + 1]);
    }
}

int range()//判定表格是否全部一样
{
    int i, j;
    for (i = 0; i < 4; i++)
    {
        for (j = 0; j < 4; j++)
        {
            if (map[i][j] != map[0][0])
            {
                return 0;
            }
        }
    }
    return 1;
}

int DFS(int i, int j, int dp)//深搜(dp<=step)
{
    //对第dp次的转换作判断
    if (dp == step)
    {
        flag = range();
        return 0;
    }
    if (flag || i == 4)
    {
        return 1;
    }

    //没有以上两种可以直接退出函数的情况,
    //说明此时的dp<step,就进行第dp+1次的转换
    turn(i, j);   

    //对第dp+1次的转换进行判断
    if (j < 3)
    {
        //判断的是第dp+1次时转换的turn(i,j),
        //如果判断成功,直接退出函数。
        //如果判断失败,要继续进行下一列(即j+1)的递归转换和判断
        //j+1不影响对第dp+1次转换的turn(i,j)的判断
        //因为在DFS()函数里,判断turn(i,j)的步骤总在turn(i,j+1)前面
        DFS(i, j+1, dp + 1);
    }
    else
    {
        //判断的是第dp+1次时转换的turn(i,j),
        //如果判断成功,直接退出函数。
        //如果判断失败,要继续进行下一行(即i+1)的递归转换和判断
        //i+1不影响对第dp+1次转换的turn(i,j)的判断
        //因为在DFS()函数里,判断turn(i,j)的步骤总在turn(i+1,j)前面
        DFS(i + 1, 0, dp+1);
    }

    turn(i, j);      //不符合条件,重新转换回来

    //第dp次时,表格恢复初始状态
    if (j < 3)
    {
        DFS(i, j + 1, dp );   //进行对下一列进行第dp次的转换()
    }
    else
    {
        DFS(i + 1, 0, dp);    //进行对下一行进行第dp次的转换
    }

    return 0;

}

int main()
{
    char a;
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            scanf("%c", &a);
            if (a == ‘b‘)
            {
                map[i][j] = 0;
            }
            else
            {
                map[i][j] = 1;
            }
        }
        getchar();    //不要遗忘
    }

    for (step = 0; step <= 16; step++)
    {
        flag = 0;
        DFS(0, 0, 0);
        if (flag)
            break;
    }
    if (flag)
    {
        printf("%d\n", step);
    }
    else
    {
        printf("Impossible\n");
    }

    return 0;

}
时间: 2024-08-07 13:50:35

Poj1753 翻转棋子的相关文章

POJ1753——Flip Game

Flip Game Description Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the other one is black and each piece is lying either it's black or white side up. Each r

POJ1753:Flip Game

Flip Game Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 29713   Accepted: 12876 Description Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the

POJ1753 状态压缩(+BFS) + 棋盘问题

0 棋盘问题,改变一个子的颜色,这个子以及这个子周围的四个位置(左右上下)的子分别变色,求最少的改变次数. 此类题大部分应该可以用状态压缩+暴力搜索解决.纯粹找规律不太合理. 1)第一种方法,状态压缩后BFS暴力搜索.因为棋盘很小,只有16个格子,枚举所有的状态共有2^16=65536种.所以有可以用int数组存储65535个状态用以确认哪一个出现了哪一个没出现,然后暴力枚举+BFS的搜索方式. 2)第二种,或者不进行状态压缩,直接按顺序,确定改变次数为1.改变次数为2...改变次数为16,在每

POJ 3279 Fliptile(翻转)

题目链接:http://poj.org/problem?id=3279 题意:n*m棋盘区域,由0和1填充,0白,1,黑,(正反两面颜色各异)通过翻转操作使棋盘全部白色朝上,每次翻转棋子,棋子周围(上下左右)都要被翻转,问是否可能翻转 翻转成功,如果翻转成功,输出最少的翻转次数下每个棋子的翻转次数. 题解:有m列,所以最多有2^m种可能性,枚举第一行.然后从第i行(i从2开始)先开始考虑第i-1行,然后依次往下推,再判断最后一行是不是都翻转成白色. 1 #include <string> 2

[暴力]poj1166

题意: 给出9[A-I]个表,9中操作,每种操作只能拨动部分表, Move Affected clocks 1 ABDE 2 ABC 3 BCEF 4 ADG 5 BDEFH 6 CFI 7 DEGH 8 GHI 9 EFHI 问,最少几步把表都拨到12点? 分析: 这个题每种拨法不能超过4次,这就类似翻转棋子了,4次就回到了原来的地方,没必要.所以,那问题就简化很多了,每种操作不多于3次.那如何选择最短路呢?因为这些顺序是无关的,先执行哪个动作都可以,所以顺序是可以随便写的.改变顺序不影响结果

POJ_1753——Flip Game(枚举)

Flip Game Time Limit: 1000MS Memory Limit: 65536K Description Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the other one is black and each piece is lying ei

POJ 1753 Flip Game (状压+暴力)

题目链接:http://poj.org/problem?id=1753 题意: 给你一个4*4的棋盘,上面有两种颜色的棋子(一种黑色,一种白色),你一次可以选择一个棋子翻转它(黑色变成白色,同理反之),选择的这枚棋子的上下左右都会被翻动(前提是上下左右都可以被翻动).问最少可以翻动多少颗棋子,让整个棋盘变成全部黑色或者全部白色. 题解: 4*4一共就16个格子,每个格子都可以是翻或者不翻,那么就是216翻法. 所以就可以用状态压缩的方法来解决. 比如说47. 47的二进制是00101111,我们

位运算+枚举

位运算http://c.biancheng.net/cpp/html/101.html 在很多情况下(比如翻棋子)在搜索时涉及大量枚举往往导致超时,位运算则很好地解决了这个问题,方便又快捷 HDU  1882   Strange Billboard http://acm.hdu.edu.cn/showproblem.php?pid=1882 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot

poj 1753 Flip Game (bfs + 枚举)

链接:poj 1753 题意:这是翻棋游戏,给定4*4棋盘,棋子一面为黑色(用b表示),另一面为白色(用w表示),问至少要几步可以将棋子翻为全黑或者全白,如不能达到目的,输出"Impossible " 翻转规则:可以选定16个棋子中的任意一个,将其本身以及上下左右相邻的翻转过来 分析:其实每格棋子最多只可以翻转一次(实际是奇数次,但与翻转一次状态一样),只要其中一格重复翻了2次(不论是连续翻动还是不连翻动),那么它以及周边的棋子和没翻动时的状态是一致的,与最初状态未翻转一样,由此就可以