POJ 1753 Flip Game 题解

POJ 1753 Flip Game 题解

题目解读

原题摘录
读到这个题目,首先要明确题目要求完成的任务。这道题的背景是翻转棋游戏。翻转棋游戏以4*4的棋盘为背景,有黑白两种颜色的棋子。现在题目中给出了在某一时刻棋盘上棋子的分布,要求每一回合选择棋盘上的某一个坐标,通过翻转规则作用棋盘发生变化。问最少经过几个回合能使得棋盘上的棋子变成全白或者全黑的状态。
显然,题目的重点在翻转规则:该游戏中,将选择修改的坐标棋子及其上下左右方向的棋子,共计五个进行翻转修改(如果上下左右有棋子的话则翻转,否则不翻转)。

解决算法

对题目进行抽象,比较容易想到的就是采用广度优先算法(BFS),通过逐层搜索,达到目标。现在先明确BFS中的几个关键变量。

关键变量 本题中的对象
目标状态 棋盘上达到全白或者全黑
基本状态 棋盘上当前时刻黑白棋子的分布
状态转移 翻转规则:变换坐标以及上下左右共计五个棋子

第一个问题:如何表示棋盘状态?
在这里,我做题时思考了两种方法,一是直接利用string类字符串来记录整个棋盘,可以将棋盘存储为一个字符数组,然后通过函数转换成为字符串;二是观察到棋盘共计16个位置,刚好是一个short int的长度,因此可以考虑用二进制压缩的形式来表示棋盘。事实证明,这种二进制表示的形式有较快的运算速度,也不会出现超时的情况。

第二个问题:如何进行状态判重?
在广搜中,提高搜索效率,避免程序超时的很重要的方法就是进行剪枝操作,细化之后就是状态判重。之前在做广搜的题时,我会选择将其转换为整型数组,然后乘上10的幂次相加得到一个和来表示状态。这样做运算量大,而且有的时候计算结果会超出变量表示范围。这道题可以很容易分析得到棋盘的变化情况共有2^16次方共计65536种可能。一种思路是利用C++ STL中的map结构,向map中添加新的状态,通过map.find()和map.count()两种方法来检验判重;另一种思路是延续二进制的方法,通过开辟label[65536]的数组来标记是否已有该状态。不过第二种方法可能会浪费存储空间,但在寻找判重的时间上应该会略快于find()和count()方法。这里有一个小的trick就是,无论使用map还是label数组,都可以将它们对应的值用来表示到达这一状态所需的最少步骤,从而省去了另外开辟变量来记录的步骤。当然如果要是需要打印出变换路径,还是需要其他辅助变量的。

第三个问题:如何进行状态变换?
这里我以二进制压缩的方法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值