POJ 1753 Flip Game(类似与N皇后问题的DFS)
2015-08-18 12:53
429 查看
在网上看了很多人的代码,我觉得大部分人用的思想是差不多的。枚举+DFS.但是由于他们为了代码的简洁性,省去了一些代码,从而使得刚学习搜索的人云里雾里。在这里,我的代码将结合简单的N皇后问题,来说一说我对这道题的看法.
首先来看DFS的框架
![](http://img.blog.csdn.net/20150818122745402?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
在这里我们再贴出N皇后的DFS过程
N皇后的思路是假设第i-1行已经合法,到了此时的第i行,分别再各列放上棋子经行试探,合法则往下递归。这样当所有行试探完后得到的结果必定合法。拿上述代码和DFS框架比较,可知是基本符合的。
----------------------------------------------------------------------丑陋的分割线------------------------------------------------------------------------------------------------------------------------------------------
接着我们来看这道flip game.由于限定了棋盘大小4*4,所以我们只需对最后的棋盘状态进行判定是否符合要求即可。
那如何进行DFS呢?
我们想一下N皇后问题.N皇后问题中有的N行代表DFS的N层,每一行有多少列就代表该层有多少种情况。因为按照规则,每一行只能放一个棋子.
而flip game.这里对应的就是每一个点,对应的只有两种操作,翻或者不翻。
所以flip game 中的每一个点就代表一层,16个点代表16层,每一层只有两种情况。
这样通过类比,我们自然就得出了此题的DFS.即按照从上至下,从左到右的方法进行DFS.
注意的是题目是要求最小值,故需要对每次符合要求的结果与当前结果进行比较。
以下为AC的代码
首先来看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; }
相关文章推荐
- Activity 生命周期
- 基于Volley,Gson封装支持JWT无状态安全验证和数据防篡改的GsonRequest网络请求类
- thinking in java 学习笔记(一)
- HDU 2616 Kill the monster (暴力搜索 || 终极全阵列暴力)
- NodeJS简介
- Oracle 中查看用户建立的所有触发器
- Android对话框的几种形式
- 左右小移动
- Ubuntu14.04 安装 Oracle 11g R2 Express Edition
- Java深度历险(六)——Java注解 2015.8.18
- Keepalived+Nginx提供前端负载均衡+主从双机热备+自动切换
- 嵌入式OS入门注意事项-同RTX案件:九.关于优先-翻转,继承和天花板
- 蛙泳,蝶泳,仰泳,自由泳
- HTML5游戏实战之20行代码实现打地鼠
- LightOJ 1112 Curious Robin Hood (单点更新+区间求和)
- johari窗口
- ubuntu安装好后 ssh进入出错 access denied
- Java多线程实践之—终结
- Effective C++ 条款4 确定对象被使用前已被初始化
- 编写高质量代码改善C#程序的157个建议——建议69:应使用finally避免资源泄漏