HDU 1401 Solitaire 双向DFS

题意

给定一个\(8*8\)的棋盘,棋盘上有4个棋子。每一步操作可以把任意一个棋子移动到它周围四个方向上的空格子上,或者可以跳过它四个方向上的棋子(就像跳棋那样)。给定初始状态和末状态,问能否在8步之内,从初始状态变换到末状态。

解题思路

这是是看的学长写的题解,很好,也算自己简单知道了双向BFS是什么情况了。

给定了初始状态和末状态,又有最多只能走8步的限制,所以我们很容易就可以想到进行双向BFS。但是一定要注意对冗余状态的剪枝。我们可以对这四枚棋子按照某种顺序进行排序,这样就可以去掉很多等效局面,大大降低时间复杂度。

我们可以通过Hash,把一个局面Hash成一个整数\(hashVal\),然后用\(vis[hashVal]\)来记录达到这个局面一共走了多少步。当搜索结果相交的时候,判断一下当前的步数是否小于等于8即可,具体见代码。

这里还要注意,因为是双向BFS,所以每次循环这两个BFS都会走一步,因而每个BFS最多只能走4步

代码实现

#include <map>
#include <queue>
#include <cstdio>
#include <algorithm> using namespace std;
typedef long long ll;
const ll BASE = 100;
const int MAXN = 8 + 2;
const int nextS[][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int mp[MAXN][MAXN];
struct Node {
int x[4], y[4];
} st, ed; inline bool check(int x,int y)
{
if (x > 8 || x < 1 || y > 8 || y < 1) return false;
else return true;
}
//专门写的一个哈希函数,对于每个状态转化为一个数,这里是真的难
ll getHashVal(Node a) {
int temp[4];
ll ret = 0;
for (int i = 0; i < 4; i++)
temp[i] = (a.x[i] - 1) * 8 + a.y[i];
sort(temp, temp + 4);
for (int i = 3; i >= 0; i--)
ret = ret * BASE + temp[i];
return ret;
} bool bfs() {
int step = 0;
queue<Node> q1, q2;
map<ll, int> vis1, vis2;
Node now, temp;
q1.push(st), q2.push(ed);
vis1[getHashVal(st)] = 0, vis2[getHashVal(ed)] = 0;
while (true)
{
now = q1.front();
q1.pop();
int nowHashVal = getHashVal(now);
if (vis1[nowHashVal] > 4) break;//这里大于4就要跳出
for (int i = 0; i < 4; i++)
mp[now.x[i]][now.y[i]] = 1;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
int nextX = now.x[i] + nextS[j][0], nextY = now.y[i] + nextS[j][1];
if (check(nextX, nextY)==false) continue;
if (mp[nextX][nextY]) //如果这个点有棋子了,那么就要跳过再走一次。
{
nextX += nextS[j][0], nextY += nextS[j][1];
if (check(nextX, nextY)==false || mp[nextX][nextY]) continue;
}
temp = now;
temp.x[i] = nextX, temp.y[i] = nextY;
int tempHashVal = getHashVal(temp);
if (vis1.find(tempHashVal) == vis1.end())
{
vis1[tempHashVal] = vis1[nowHashVal] + 1;
q1.push(temp);
if (vis2.find(tempHashVal) != vis2.end())//查找反向bfs中有没有走到这个节点的
{
step = vis1[tempHashVal] + vis2[tempHashVal];
if (step <= 8) return true;
}
}
}
}
for (int i = 0; i < 4; i++)
mp[now.x[i]][now.y[i]] = 0; now = q2.front();
q2.pop();
nowHashVal = getHashVal(now);
if (vis2[nowHashVal] > 4)break;
for (int i = 0; i < 4; i++)
{
mp[now.x[i]][now.y[i]] = 1;
}
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
int nextX = now.x[i] + nextS[j][0], nextY = now.y[i] + nextS[j][1];
if (check(nextX, nextY)==false) continue;
if (mp[nextX][nextY])
{
nextX += nextS[j][0], nextY += nextS[j][1];
if (check(nextX, nextY)==false || mp[nextX][nextY]) continue;
}
temp = now;
temp.x[i] = nextX, temp.y[i] = nextY;
int tempHashVal = getHashVal(temp);
if (vis2.find(tempHashVal) == vis2.end())
{
vis2[tempHashVal] = vis2[nowHashVal] + 1;
q2.push(temp);
if (vis1.find(tempHashVal) != vis1.end())
{
step = vis1[tempHashVal] + vis2[tempHashVal];
if (step <= 8) return true;
}
}
}
}
for (int i = 0; i < 4; i++)
mp[now.x[i]][now.y[i]] = 0;
}
return false;
} int main() {
while (scanf("%d %d", &st.x[0], &st.y[0]) != EOF) {
for (int i = 1; i < 4; i++)
scanf("%d %d", &st.x[i], &st.y[i]);
for (int i = 0; i < 4; i++)
scanf("%d %d", &ed.x[i], &ed.y[i]);
if (getHashVal(st) == getHashVal(ed)) {
printf("YES\n");
continue;
}
printf(bfs() ? "YES\n" : "NO\n");
}
return 0;
}

HDU 1401 Solitaire 双向DFS的更多相关文章

  1. POJ 1198 / HDU 1401 Solitaire (记忆化搜索+meet in middle)

    题目大意:给你一个8*8的棋盘,上面有四个棋子,给你一个初始排布,一个目标排布,每次移动,可以把一个棋子移动到一个相邻的空位,或者跨过1个相邻的棋子,在保证棋子移动不超过8次的情况下,问能否把棋盘上的 ...

  2. HDU 1269.迷宫城堡-Tarjan or 双向DFS

    迷宫城堡 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  3. HDOJ(HDU).2660 Accepted Necklace (DFS)

    HDOJ(HDU).2660 Accepted Necklace (DFS) 点我挑战题目 题意分析 给出一些石头,这些石头都有自身的价值和重量.现在要求从这些石头中选K个石头,求出重量不超过W的这些 ...

  4. HDOJ(HDU).1045 Fire Net (DFS)

    HDOJ(HDU).1045 Fire Net [从零开始DFS(7)] 点我挑战题目 从零开始DFS HDOJ.1342 Lotto [从零开始DFS(0)] - DFS思想与框架/双重DFS HD ...

  5. HDOJ(HDU).1241 Oil Deposits(DFS)

    HDOJ(HDU).1241 Oil Deposits(DFS) [从零开始DFS(5)] 点我挑战题目 从零开始DFS HDOJ.1342 Lotto [从零开始DFS(0)] - DFS思想与框架 ...

  6. HDOJ(HDU).1035 Robot Motion (DFS)

    HDOJ(HDU).1035 Robot Motion [从零开始DFS(4)] 点我挑战题目 从零开始DFS HDOJ.1342 Lotto [从零开始DFS(0)] - DFS思想与框架/双重DF ...

  7. HDU 1501 Zipper 【DFS+剪枝】

    HDU 1501 Zipper [DFS+剪枝] Problem Description Given three strings, you are to determine whether the t ...

  8. 送礼物(二分加双向DFS)

    题目链接 题意:给你n个礼物重量,给你一个M力量,看你一次性搬动不超过M的礼物重量. 思路:看似背包,但M太大.所以要用DFS,但n也有45,所以考虑双向DFS先搜前半部分满足情况的所有重量,然后去重 ...

  9. poj 1198 hdu 1401 搜索+剪枝 Solitaire

    写到一半才发现能够用双向搜索4层来写,但已经不愿意改了,干脆暴搜+剪枝水过去算了. 想到一个非常水的剪枝,h函数为  当前点到终点4个点的最短距离加起来除以2.由于最多一步走2格,然后在HDU上T了, ...

随机推荐

  1. [模板] 计算几何2: 自适应Simpson/凸包/半平面交/旋转卡壳/闵可夫斯基和

    一些基本的定义在这里: [模板] 计算几何1(基础): 点/向量/线/圆/多边形/其他运算 自适应Simpson Simpson's Rule: \[ \int ^b_a f(x)dx\approx ...

  2. TTTTTTTTTTTTT CF Good Bye 2015 C- New Year and Domino(CF611C) 二维前缀

    题目 题意:给你一个n*m由.和#组成的矩阵,.代表可以放,#代表不可以,问在左上角(px,py)到(右下角qx,qy)这样的一个矩阵中,放下一个长度为2宽度为1的牌有多少种放法: #include ...

  3. 【BZOJ2459】 [BeiJing2011]神秘好人

    Description 有一个神秘好人跟Bdcxq玩一个游戏,如果Bdcxq成功完成了这个游戏,那么他将会得到一件礼物. 这个游戏是这样的: 有一个梯子形的图如下,每条边都有一个权值. 神秘好人一开始 ...

  4. 在spring官网上下载历史版本的spring插件,springsource-tool-suite

    目前spring官网(https://spring.io/tools3/sts/all)上可下载的spring插件只有: ECLIPSE ARCHIVE SIZE 4.9.0 springsource ...

  5. @Transient使用心得

    使用注解@Transient使表中没有此字段 注意,实体类中要使用org.springframework.data.annotation.Transient 在写实体类时发现有加@Transient注 ...

  6. Springboot 使用 webSocket

    介绍 WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议.在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进 ...

  7. 程序代码运行结果是(abdcbdcb)

    public class Test { public static boolean show(char ch) { System.out.print(ch); return true; } publi ...

  8. C++入门经典-例5.20-右值引用传递参数

    1:使用字面值(如1.3.15f.true),或者表达式等临时变量作为函数实参传递时,按左值引用传递参数会被编译器阻止.而进行值传递时,将产生一个和参数同等大小的副本.C++11提供了右值引用传递参数 ...

  9. IDEA 无法显示项目目录结构解决

    不要去网上看什么乱七八糟的骚教程,一点用都没有.直接按下列步骤操作: 1. 关闭IDEA, 2. 然后删除项目文件夹下的.idea文件夹3. 重新用IDEA工具打开项目

  10. vue开发多页面应用

    1.添加多页面配置 在工程根路径下(package.json同目录)添加添加vue.config.js配置文件,内容为: module.exports = { pages: { index: 'src ...