学习随笔——POJ题目1753:Flip Game解答

本题题目链接:http://poj.org/problem?id=1753

题目截图如下:

 题目大意:在4*4棋盘上有黑白子若干,现需要翻动若干次棋盘上的棋子实现棋盘上的棋子全白或全黑。翻动的规则是:当翻动某一棋子时,其上下左右棋子也需被翻动。求翻动的最小次数,如果无法实现,则需要输出提示信息“Impossible”。

一道枚举的题目,根据分析,我们很容易知道同一个位置的棋子翻动两次与未翻动的状态相同,所以每个位置的棋子我们就可简化为翻动与不翻动两种状态。这样只需确定16个位置的翻动状况即可。同样的,如果最后翻动次数大于16我们可以判定为不存在一种翻动的可行方案。

先放上代码,之后会对递归过程进行详细讲解:

 1 #include <stdio.h>
 2 #include <iostream>
 3 using namespace std;
 4 int mem[16] = {0};//化二维为一维的数组 
 5 int ans = 100;//最后返回的回答
 6 void change (int pos){
 7     int x = pos/4;//判断边界条件 
 8     int y = pos%4;//判断边界条件 
 9     mem[pos] = !mem[pos];//先改变目标点 
10     if (x>0)
11         mem[pos-4] = !mem[pos-4];
12     if (x<3)
13         mem[pos+4] = !mem[pos+4];
14     if (y>0)
15         mem[pos-1] = !mem[pos-1];
16     if (y<3)
17         mem[pos+1] = !mem[pos+1]; 
18 }//pos为要改变的点的坐标
19 bool Judge (){
20     for (int i = 0;i<15;i++){
21         if (mem[i] != mem[i+1])
22             return false;
23     }
24     return true;
25 }//判断是否实现预定目标 
26 void Enum (int pos,int count){
27     if (Judge())
28         if (count < ans){
29             ans = count;
30             return ;
31         }
32     if (pos >= 16)
33         return ;
34     change (pos);
35     Enum (pos+1,count+1);
36     change (pos);
37     Enum (pos+1,count);
38     return ;
39 }
40 int main (int argc,char *argv[]){
41     char start;
42     for (int i=0;i<16;i++){
43         cin>>start;
44         if (start=='b'){
45             mem[i]=1;
46         }
47     }
48     Enum (0,0);
49     if (ans==100)
50         printf("Impossible");
51     else
52         printf("%d",ans);
53     return 0;
54 }

对递归部分的讲解:

1 change (pos);
2 Enum (pos+1,count+1);
3 change (pos);//复位操作
4 Enum (pos+1,count);

      我对于这四条语句的理解是,我们把它理解为一种状态的转换:每一个位置有翻与不翻两种状态,其中1、2两句即表示该位置棋子翻转,并将该状态输入函数的过程。第三句实际上实现了一种“复位”操作,将原来翻转的棋子再翻转回来,再将该位置棋子未翻转的状态输入函数。或者我们更进一步理解,每个点的翻转与否构成了一个二叉树,我们找到最小值的过程就是对这个树进行深度遍历的过程。事实上,上述语句改编为以下形式亦可。

1 Enum (pos+1,count);
2 change (pos);
3 Enum (pos+1,count+1);
4 change (pos);//复位操作
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POJ1753题目为"Flip Game",题目给出了一个4x4的棋盘,每个格子有黑色或白色,每次翻转一个格子会同时翻转它上下左右四个格子的颜色,目标是把整个棋盘都变为同一种颜色,求把棋盘变成同种颜色的最小步数。 解题思路: 一般关于棋盘变色的题目,可以考虑使用搜索来解决。对于POJ1753题目,可以使用广度优先搜索(BFS)来解决。 首先,对于每个格子,定义一个状态,0表示当前格子是白色,1表示当前格子是黑色。 然后,我们可以把棋盘抽象成一个长度为16的二进制数,将所有格子的状态按照从左往右,从上往下的顺序排列,就可以用一个16位的二进制数表示整个棋盘的状态。例如,一个棋盘状态为: 0101 1010 0101 1010 则按照从左往右,从上往下的顺序把所有格子的状态连接起来,即可得到该棋盘的状态为"0101101001011010"。 接着,我们可以使用队列来实现广度优先搜索。首先将初始状态加入队列中,然后对于队列中的每一个状态,我们都尝试将棋盘上的每个格子翻转一次,生成一个新状态,将新状态加入队列中。对于每一个新状态,我们也需要记录它是从哪个状态翻转得到的,以便在得到最终状态时能够输出路径。 在搜索过程中,我们需要维护每个状态离初始状态的步数,即将该状态转换为最终状态需要的最小步数。如果我们找到了最终状态,就可以输出答案,即最小步数。 代码实现:

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值