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. Codeforces 1213F Unstable String Sort

    cf题面 中文题意 求一个由最多26个.最少k个小写字母构成的,长度为n的字符串,这个字符串要满足的要求是--当其中字母按照p和q两个\(1\)~\(n\)的全排列重新排序时,新的字符串是按照升序排好 ...

  2. vue路由 routers的写法:require用与不用

    vue路由的写法有很多种,这里我只说routers的写法,一种是compcomponent后面直接写路径,另一种是用require的方式,来看代码 import Vue from 'vue' impo ...

  3. Spring Boot教程(三十二)多数据源配置与使用(2)

    Spring-data-jpa支持 对于数据源的配置可以沿用上例中DataSourceConfig的实现. 新增对第一数据源的JPA配置,注意两处注释的地方,用于指定数据源对应的Entity实体和Re ...

  4. python学习之路(6)

    使用dict和set Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度. 举个例子,假设要根 ...

  5. JQuery实现表格动态增加行并对新行添加事件

    实现功能: 通常在编辑表格时表格的行数是不确定的,如果一次增加太多行可能导致页面内容太多,反应变慢:通过此程序实现表格动态增加行,一直保持最下面有多个空白行. 效果: 一:原始页面 二:表1增加新行并 ...

  6. TensorFlow写的神经网络不work的原因

    for epoch in range(training_steps): with tf.Session() as sess: sess.run(tf.global_variable_initializ ...

  7. JS 类和继承

    function User(name, pass) { this.name = name this.pass = pass } User.prototype.showName = function ( ...

  8. AES加密算法在Linux下出现随机加密结果

    特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...

  9. tensorflow实现LeNet-5模型

    网络结构如下: INPUT: [28x28x1] weights: 0 CONV5-32: [28x28x32] weights: (5*5*1+1)*32 POOL2: [14x14x32] wei ...

  10. 怎样用 Bash 编程:逻辑操作符和 shell 扩展

    学习逻辑操作符和 shell 扩展,本文是三篇 Bash 编程系列的第二篇. Bash 是一种强大的编程语言,完美契合命令行和 shell 脚本.本系列(三篇文章,基于我的 三集 Linux 自学课程 ...