Flip Game(2021-TRN1-K)

Flip Game(2021-TRN1-K)

题目大意

传送门

这个和poj 1222有点类似(其实那道题更难一点)
大意是说,在一个4*4的棋盘上面(姑且称作棋盘)的每一个格子里都放着一个棋子。棋子比较特殊,一面是黑的,一面是白的。可以通过翻棋子来改变棋子的颜色。每翻一个棋子,这个棋子的颜色肯定变了,而该棋子周围的棋子也会随之变颜色。
求最少的步骤。

题目解析

典型的DFS,不需要太多的剪枝。这个论断的得出是因为DFS的本质是枚举。而显然,每一个棋子我们都可以选择翻开或者不翻开,一共就有2^16次方种可能。这个计算量是很小的。而poj 1222那道题格子更多,暴力DFS可能就会超时了。
怎么枚举呢?就是从左到右,从上到下。枚举两种情况:翻开了,或者不翻开来。这种枚举不是没见过。然后回溯。

然而做的时候还是捉襟见肘,居然一开始还没有意识到有的棋子可以不翻开 还有就是写DFS有一段时间没写,手生了,连step作为函数参数,还有哪些要回溯一开始都没有想清楚,人没了。。。

代码

#include <bits/stdc++.h>

using namespace std;
int a[5][5];
char str[5][5];
int dir[4][2]={
    
    {
    
    1,0},{
    
    0,1},{
    
    -1,0},{
    
    0,-1}};
int mini=1e8;
int check()
{
    
    
    int i,j,sum=0;
    for(i=1;i<=4;i++)
    {
    
    
        for(j=1;j<=4;j++)
        {
    
    
            sum+=a[i][j];
        }
    }
    if(sum==0||sum==16) return 1;
    return 0;
}
void flip(int x,int y)
{
    
    
    a[x][y]^=1;
    for(int k=0;k<4;k++)
    {
    
    
        int newx=x+dir[k][0];
        int newy=y+dir[k][1];
        if(newx>=1&&newx<=4&&newy>=1&&newy<=4)
        {
    
    
            a[newx][newy]^=1;
        }
    }
}
void dfs(int x,int y,int step)
{
    
    
    if(step>16) return;///16个格子都翻过了,不用继续深搜
    if(check())
    {
    
    
        if(step<mini) mini=step;
        return;
    }
    if(y>=5)
    {
    
    
        x++;
        y=1;
    }
    if(x>=5) return;

    flip(x,y);
    dfs(x,y+1,step+1);///翻开棋子
    flip(x,y);///回溯

    dfs(x,y+1,step);///不翻开棋子
}
void init()
{
    
    
    int i,j;
    for(i=1;i<=4;i++)
    {
    
    
        for(j=0;j<4;j++)
        {
    
    
            if(str[i][j]=='b') a[i][j+1]=1;
            else a[i][j+1]=0;
        }
    }
}
int main()
{
    
    
    int i;
    for(i=1;i<=4;i++)
    {
    
    
        gets(str[i]);
    }
    init();
    dfs(1,1,0);
    if(mini<=16) printf("%d\n",mini);
    else printf("Impossible\n");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/booniebears/article/details/112971282