据说还可以用bfs加上位压缩来做,但是蒟蒻不会。。。嘤嘤嘤😭,还是看了别人的题解才打出来的dfs。。。
先说一下这道题的思路,还是建树的思想,按位枚举的搜索顺序,每个节点有两个分支:翻或者不翻,然后再走到上下左右的格子上。因为要求的是最短的翻牌数,所以每次到达目标状态的时候要将最终答案ans和现在的cnt取一个最小值赋给ans。另外说一下一个简便方法,因为这个矩阵也不是很大,我们可以把二维的字符点阵压缩成一维的字符串来比较就可以啦😀
下面是代码,有比较详细的注释:
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <map>
#define N 50
using namespace std;
// map<string, bool> vis; // 按位搜索不会重复,没必要记录用vis记录状态是否出现过
string modela = "wwwwwwwwwwwwwwww", modelb = "bbbbbbbbbbbbbbbb"; // 目标字符串
string str; // 输入的字符串
int ans = N; // 先将ans初始化成一个较大的数,方便到时候取min
int dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0}; // 位移数组
int bw = 'b' + 'w'; // 就是懒得每一遍都打,用一个变量存一下
void turn(int x, int y)
{
int k = x * 4 + y; // 找到在字符串中对应的下标
str[k] = char(bw - str[k]); // 小技巧:翻牌就是用两面加起来的值减去现在这一面的值
for (int i = 0; i < 4; i ++)
{
int xx = x + dx[i], yy = y + dy[i];
if(xx >= 0 && xx < 4 && yy >= 0 && yy < 4) // 注意:每次位移一定要判断是否越界
{
int t = xx * 4 + yy;
str[t] = char(bw - str[t]);
}
}
}
void dfs(int x, int y, int cnt)
{
if(str == modela || str == modelb) // 如果搜到了模板串,就取最小值,然后结束
{
ans = min(ans, cnt);
return;
}
if(y == 4) x ++ , y = 0; // 遇到该换行的时候了
if(x == 4) return; // 所有行都枚举完毕,都还没有找到,返回即可
// 不翻,直接看下一个位置
dfs(x, y + 1, cnt);
// 翻
turn(x, y);
// if(!vis[str])
// {
// vis[str] = true;
dfs(x, y + 1, cnt + 1);
// vis[str] = false;
// }
turn(x, y); // 记得要恢复现场
}
int main()
{
for(int i = 0; i < 4; i ++)
{
char ch[5]; // 用char数组来读入可以忽略回车
scanf("%s", ch);
str += ch;
}
dfs(0, 0, 0); // 随便从哪一个点开始搜都可以,这里是从(0, 0)开始的
if(ans != N) printf("%d\n", ans);
else puts("Impossible");
return 0;
}

本文深入探讨了一款翻转游戏的解决方案,采用深度优先搜索(DFS)算法,结合位操作实现状态压缩,以求得最少翻转次数达到目标状态。文章详细解释了算法思路,包括构建树状结构,枚举行为,以及如何通过状态比较优化搜索过程。

1375

被折叠的 条评论
为什么被折叠?



