题目大意

有一个4×4的棋盘,上面放满棋子,棋子一面是白色,另一面是黑色。每次翻转一枚棋子,同时与这枚棋子相邻的上下左右的棋子也要翻转。问能否通过数次翻转使得所有的棋子全部白色面朝上或全部黑色面朝上呢?如果不可以,输出 “Impossible”(没有引用号),如果可以,输出最小翻转次数。

样例输入

bwwb
bbwb
bwwb
bwww

样例输出

4

思路

我们贪心地思考这个问题。假如最后我们的目标是全部为白色。对于棋盘第一行,我们可以尝试全部24=162^4=1624=16种可能的翻转操作(相当于为16棵搜索树分别建立了根节点)。然后对于第二行,我们需要通过翻转带动将第一行的黑色棋子全部翻转为白色。同时在第二行翻转的这一棋子也会带动左右和第三行的棋子状态改变,我们实时更新这一状态即可。以此类推,直到上面三行的棋子全部翻转为白色,我们再来看第四行,如果第四行的棋子也全为白色,则方案可行。否则,方案失败。假设最后目标是全部为黑色,也是同理。

如何实现这一过程呢?最快的方法是用位运算。由于0^0=0, 1^1=0, 0^1=1, 1^0=1,故1表示翻转,0表示不翻转。直接用0000~1111的二进制数按位异或第一行,即得到16种状态(天雾辰明流剑术中传)。

要表示翻转的棋子左边棋子也要翻转,设给出一种翻转情况为0110,则需要再按位异或((0110)<<1)=1100 ,即表示翻转状态向左侧传递一位(天雾辰明流剑术左传)。如果遇到1100这类反转情况,再让棋盘上这一行的状态按位异或((1100)<<1)=11000显然是错误的,这样棋盘上这一行的状态对应的二进制数从右向左第五位一定是0,0^1=1,这样按位异或后得到的状态对应的二进制数超出了1111,即不存在。为纠正这一错误,应令原状态按位异或(((1100)<<1)&1111)=1000,即通过与运算1111消除第五位以后的1带来的影响(1&0=0)。

要表示翻转的棋子右边棋子也要翻转,设给出一种翻转情况为0110,则需要再按位异或((0110)>>1)=0011 ,即表示翻转状态向右侧传递一位(天雾辰明流剑术右传)。

棋盘上某一行当前的状态对应的就是下一行和下下行(状态向下传递)应该按位异或的二进制串。均以某位为0表示无需翻转,为1表示需要翻转。在读入时可以分类讨论,一类终点是全白,就令白色为0,黑色为1;另一类是终点全黑,就令黑色为0,白色为1。具体细节见代码。

考点

位运算
状压
枚举和暴力
模拟
贪心

AC代码(含注释)

#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 0x3f3f3f3f;
int ed_white[5], ed_black[5], num[(1<<4)+5];
int ans = maxn;
int get_step(int now) {//将十进制化为二进制统计1的个数int cur_step = 0;while (now) {if (now & 1)cur_step++;now = now >> 1;}return cur_step;
}
int search(int row[]) {int cur_row[6], cur_ans = maxn;for (int i = 0; i<(1 << 4); i++) {//遍历第一行的全部16种翻转可能cur_row[1] = row[1] ^ ((i << 1) & 0xf) ^ i ^ (i >> 1);//翻转第一行cur_row[2] = row[2] ^ i;//状态下传,带动翻转第二行int step = num[i]; //记录这种翻转可能对应的翻转步数for (int j = 2; j <= 4; j++) {cur_row[j] = cur_row[j] ^ ((cur_row[j - 1] << 1) & 0xf) ^ cur_row[j - 1] ^ (cur_row[j - 1] >> 1);//翻转第j行cur_row[j + 1] = row[j + 1] ^ cur_row[j - 1];//状态下传step += num[cur_row[j - 1]];//记录步数}if (!cur_row[4])cur_ans = min(cur_ans, step);//方案成功,更新答案}return cur_ans;
}
int main() {char x;for (int i = 1; i <= 4; i++) {for (int j = 0; j < 4; j++) {scanf(" %c", &x);if (x == 'b')ed_white[i] |= (1 << j);//记录二进制每一位else ed_black[i] |= (1 << j);}}for (int i = 1; i < (1 << 4); i++)num[i] = get_step(i);//异或数在0~15之间int ans_white = search(ed_white), ans_black = search(ed_black);//分别统计全黑和全白的最小步数ans = min(ans_white, ans_black);//取公共最小步数ans == maxn ? puts("Impossible") : printf("%d", ans);//答案不为maxn,说明可以达成目标return 0;
}

心得

本题是一道很好的二进制状态压缩的练手题。对上下左右状态的传递模拟用二进制语言描述尤其不好想。得出本题的思路也用到了贪心,即先给出一种可能的翻转情况,这样后续每行都可以用贪心的翻转方式去弥补上一行的不足,直到最后一行再去判断是否成立。本题值得仔细品味。

POJ1753 翻转游戏 题解相关推荐

  1. LeetCode 294. 翻转游戏 II(记忆化递归)

    文章目录 1. 题目 2. 解题 1. 题目 你和朋友玩一个叫做「翻转游戏」的游戏, 游戏规则:给定一个只有 + 和 - 的字符串. 你和朋友轮流将 连续 的两个 "++" 反转成 ...

  2. LeetCode 293. 翻转游戏

    文章目录 1. 题目 2. 解题 1. 题目 你和朋友玩一个叫做「翻转游戏」的游戏,游戏规则:给定一个只有 + 和 - 的字符串. 你和朋友轮流将 连续 的两个 "++" 反转成 ...

  3. 20200208(补):翻转游戏Ⅰ Ⅱ(leetcode)

    翻转游戏Ⅰ& Ⅱ 题目 思路与算法 代码实现 题目 翻转游戏Ⅰ 翻转游戏Ⅱ 思路与算法 翻转游戏Ⅰ的意思读题容易歧义,读英文题目后理解是第一次操作后的所有list集合,因此思路很清晰,遍历,找 ...

  4. 51nod-1337:翻转游戏

    1337 翻转游戏 题目来源: TopCoder 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题  收藏  关注 这个游戏与灯有关,有M只灯排成一行,编号为0,1, ...

  5. 阿狸和桃子的游戏题解

    阿狸和桃子的游戏题解 每一道代码简单的黑题都有着诡异的思想,真不知道出题者怎么想的. 而这道题的重点在于把边权转换为点权, 此题的方式是将边权w平均分给被连接的两点u和v. 若u和v都被一人选择,则他 ...

  6. 洛谷P1129 [ZJOI2007] 矩阵游戏 题解

    洛谷P1129 [ZJOI2007] 矩阵游戏 题解 题目链接:P1129 [ZJOI2007] 矩阵游戏 题意:给定一张有黑白棋子的正方形棋盘,问存不存在解法使得经过若干次交换行或列的操作后,左上角 ...

  7. P1199(NOIP2010 普及组)三国游戏 题解

    P1199(NOIP2010 普及组)三国游戏题解 Step-1 输入(重点) 输入n:int n;cin>>n; 输入数组: int a[1001][1001]; for(int i=1 ...

  8. [Swift]LeetCode293. 翻转游戏 $ Flip Game

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ➤微信公众号:山青咏芝(shanqingyongzhi) ➤博客园地址:山青咏芝(https://www.cnblog ...

  9. NOIp2012D1T2 国王游戏 题解

    国王游戏 洛谷P1080国王游戏 题解 这道题有个重要的性质:如果交换相邻两个大臣,获得金钱变化的有且只有这两个大臣.其余大臣得到的金钱不变. 我们考虑第 i i i个大臣和第 i + 1 i+1 i ...

最新文章

  1. Linux 技术篇-使用vim命令创建、编辑文件内容实例演示,linux修改文档方法
  2. Java知识点:条件编译
  3. ALV报表复制程序标准工具栏
  4. 《数据库系统实训》实验报告——事务的应用
  5. 工作48:$emit
  6. Nacos版本升级1.1.3 >> 1.3.1 —>再升级至1.3.2
  7. 计算机的桌面教案,《认识计算机桌面》教案(4页)-原创力文档
  8. 简单的计算机英语文章,简单的英语小短文欣赏
  9. 今天,Java 12 正式发布了!
  10. 修改system.img的大小限制
  11. python的抽象类详解_Python抽象类以及元类
  12. Python就业涨薪小技巧!
  13. RocketMQ开发指导之二——RocketMQ部署
  14. camelCase骆驼拼写法
  15. 使用换IP软件的代理IP速度缓慢的原因是什么?详解!
  16. html 自定义打印模板,如何自定义打印模板
  17. 解决Untracked Files Prevent Checkout问题
  18. 码怪之程序员的日常语录
  19. 李开复《人工智能》读后感
  20. 【Python-GUI开发】四 pyqt5 UI扁平化设计

热门文章

  1. 清华大学交叉信息研究院弋力老师课题组招收科研实习生
  2. Mac Office启动报错:隐藏模块中出现编译错误:link
  3. python six 用途_python之six用法
  4. Flutter 插件开发:iOS篇
  5. 流媒体高清视频校园直播点播
  6. linux 使用scp命令,scp命令详解(全)
  7. 安卓(Android)手机如何安装APK?
  8. 微信小程序把阿里icon变为组件
  9. UIPATH IE浏览器下载问题
  10. 服务器漏洞--永恒之蓝