您的位置:首页 > 其它

POJ 1753 Flip Game(类似与N皇后问题的DFS)

2015-08-18 12:53 429 查看
在网上看了很多人的代码,我觉得大部分人用的思想是差不多的。枚举+DFS.但是由于他们为了代码的简洁性,省去了一些代码,从而使得刚学习搜索的人云里雾里。在这里,我的代码将结合简单的N皇后问题,来说一说我对这道题的看法.

首先来看DFS的框架



在这里我们再贴出N皇后的DFS过程

void queen(int i,int n)
{
if(i>n)
{
//当超过了最后一行,此时的棋盘必然是合法的,则可以输出
for(int k=1;k<=n;k++)
{
cout<<flag[k]<<" ";
}
cout<<endl;
return;
}
else
{
for(int j=1;j<=n;j++)
{
flag[i]=j;//将第i行的第j列放上一个旗子
if(IsLegal(i,j))//判断当前是否合法
queen(i+1,n);//合法则递归进入下一层
flag[i]=0;//将第i行的第j列的棋子拿掉
}
return; //所有的情况列举完毕,返回.
}
}


N皇后的思路是假设第i-1行已经合法,到了此时的第i行,分别再各列放上棋子经行试探,合法则往下递归。这样当所有行试探完后得到的结果必定合法。拿上述代码和DFS框架比较,可知是基本符合的。

----------------------------------------------------------------------丑陋的分割线------------------------------------------------------------------------------------------------------------------------------------------

接着我们来看这道flip game.由于限定了棋盘大小4*4,所以我们只需对最后的棋盘状态进行判定是否符合要求即可。

那如何进行DFS呢?

我们想一下N皇后问题.N皇后问题中有的N行代表DFS的N层,每一行有多少列就代表该层有多少种情况。因为按照规则,每一行只能放一个棋子.

而flip game.这里对应的就是每一个点,对应的只有两种操作,翻或者不翻。

所以flip game 中的每一个点就代表一层,16个点代表16层,每一层只有两种情况。

这样通过类比,我们自然就得出了此题的DFS.即按照从上至下,从左到右的方法进行DFS.

注意的是题目是要求最小值,故需要对每次符合要求的结果与当前结果进行比较。

void dfs (int i,int j,int t,int deep)
{
if ( deep>16)//到了最后一层
{
if(panduan())//当前棋盘符合题意
{
Possible=true;//判断是否有解
if(ans>t)
ans=t;
}
return ;
}
if (i >= 4 || j >= 4)
return ;

fan (i,j);//对(i,j)这一点进行翻转操作
if(j==3)//当已经到了第4列,下一次dfs就应变到下一行,第一列。下面同理
dfs (i+1,0,t+1,deep+1);//由于进行了翻转,t+1
else
dfs (i,j+1,t+1,deep+1);
//翻
 
fan (i,j);//翻回来。即对应DFS框架里的清除标记
 
if(j==3)
dfs (i+1,0,t,deep+1);//没有翻转,所以t不变
else
dfs (i,j+1,t,deep+1);
//不翻
}


以下为AC的代码

#include <stdio.h>
#include<iostream>
using namespace std;
int map[10][10],i,j;
int ans=9999999;
int Possible=false;

int panduan()
{
int x=map[0][0];
for (i=0; i<4; i++)
{
for (j=0; j<4; j++)
{
if (map[i][j]!=x)
return 0;
}
}
return 1;
}

void fan (int x,int y)
{
map[x][y]=!map[x][y];
if (x - 1 >= 0)
map[x-1][y]=!map[x-1][y];
if (x + 1 < 4)
map[x+1][y]=!map[x+1][y];
if (y - 1 >= 0)
map[x][y-1]=!map[x][y-1];
if (y + 1 < 4)
map[x][y+1]=!map[x][y+1];
}

void dfs (int i,int j,int t,int deep)
{
if ( deep>16)
{
if(panduan())
{
Possible=true;
if(ans>t)
ans=t;
}
return ;
}
if (i >= 4 || j >= 4)
return ;

fan (i,j);
if(j==3)
dfs (i+1,0,t+1,deep+1);
else
dfs (i,j+1,t+1,deep+1);
//翻
fan (i,j);
if(j==3)
dfs (i+1,0,t,deep+1);
else
dfs (i,j+1,t,deep+1);
//不翻
}

int main ()
{
char s[10];
for (i=0; i<4; i++)
{
cin>>s;
for (j=0; j<4; j++)
{
if (s[j]=='b')
map[i][j]=0;
else
map[i][j]=1;
}
}
dfs (0,0,0,1);
if (Possible==false)
cout<<"Impossible\n";
else
cout<<ans<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: