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. JS框架_(Popup.js)3D对话框窗口插件

    百度云盘 传送门 密码:afdo 3D对话框窗口插件效果: <!doctype html> <html lang="zh"> <head> &l ...

  2. supsplk 服务器被植入木马 挖矿 cpu使用 700%

    最近emr集群跑任务的时候总出现 task failed ,优化sql,调提交任务参数都没解决,最后再我排查时候,发现一个从节点的cpu使用800% 经过一些列排查,发现是被注入木马了, #被人种下的 ...

  3. @vue/cli 3.x 版本配置productionGzip提高性能

    第一步:安装插件 npm i -D compression-webpack-plugin 第二步:引入.在文件vue.config.js里导入compression-webpack-plugin,并添 ...

  4. 实现真正意义上的前后端分离------由淘宝引入nodejs引发的思考

    说起前后端分离,大家包括我自己都会想到: 当今流行的MVC不就是最标准的前后端分离吗? 说到这里,我不禁要反问,MVC真正的实现了前后端分离了吗? 无论是PHP的MVC框架TP还是JAVA的MVC框架 ...

  5. NavisWorks连接外部数据库,为模型附加属性

    可以直接从Navisworks 文件连接到外部数据库,并在场景中的对象与数据库表中的字段之间创建链接以引入额外特性. 1.连接mdb数据库 新建数据连接 单击“新建”按钮,新建数据连接,输入一个名称, ...

  6. golang 通过reflect反射修改值

    不是所有的反射值都可以修改.对于一个反射值是否可以修改,可以通过CanSet()进行检查. 要修改值,必须满足: 可以寻址 可寻址的类型: 指针指向的具体元素 slice的元素 可寻址的结构体的字段( ...

  7. 【flask】使用配置类管理app测试环境-demo版

    如果对app.config是什么还心有疑惑,或者对于这种配置方式很陌生,参考:flask项目配置 app.config classConfig.py: class BaseConfig(object) ...

  8. 第九章 SpringCloud之Zuul路由

    ############Zuul简单使用################ 1.pom.xml <?xml version="1.0" encoding="UTF-8 ...

  9. Unity旋转问题的总结

    1.物体的直接旋转 transform.Rotate();这个函数是在当前状态下网某个方向旋转.并且这里可以设置为世界空间或者自身空间. transform.rotation;这里可以通过直接定义一个 ...

  10. Cocos2d-X多线程(2) 线程的互斥量std::mutex和线程锁

    多个线程同时访问共享资源时,经常会出现冲突等.为了避免这种情况的发生,可以使用互斥量,当一个线程锁住了互斥量后,其他线程必须等待这个互斥量解锁后才能访问它. thread提供了四种不同的互斥量: 1. ...