HDU 1401 Solitaire 双向DFS
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的更多相关文章
- POJ 1198 / HDU 1401 Solitaire (记忆化搜索+meet in middle)
题目大意:给你一个8*8的棋盘,上面有四个棋子,给你一个初始排布,一个目标排布,每次移动,可以把一个棋子移动到一个相邻的空位,或者跨过1个相邻的棋子,在保证棋子移动不超过8次的情况下,问能否把棋盘上的 ...
- HDU 1269.迷宫城堡-Tarjan or 双向DFS
迷宫城堡 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- HDOJ(HDU).2660 Accepted Necklace (DFS)
HDOJ(HDU).2660 Accepted Necklace (DFS) 点我挑战题目 题意分析 给出一些石头,这些石头都有自身的价值和重量.现在要求从这些石头中选K个石头,求出重量不超过W的这些 ...
- HDOJ(HDU).1045 Fire Net (DFS)
HDOJ(HDU).1045 Fire Net [从零开始DFS(7)] 点我挑战题目 从零开始DFS HDOJ.1342 Lotto [从零开始DFS(0)] - DFS思想与框架/双重DFS HD ...
- HDOJ(HDU).1241 Oil Deposits(DFS)
HDOJ(HDU).1241 Oil Deposits(DFS) [从零开始DFS(5)] 点我挑战题目 从零开始DFS HDOJ.1342 Lotto [从零开始DFS(0)] - DFS思想与框架 ...
- HDOJ(HDU).1035 Robot Motion (DFS)
HDOJ(HDU).1035 Robot Motion [从零开始DFS(4)] 点我挑战题目 从零开始DFS HDOJ.1342 Lotto [从零开始DFS(0)] - DFS思想与框架/双重DF ...
- HDU 1501 Zipper 【DFS+剪枝】
HDU 1501 Zipper [DFS+剪枝] Problem Description Given three strings, you are to determine whether the t ...
- 送礼物(二分加双向DFS)
题目链接 题意:给你n个礼物重量,给你一个M力量,看你一次性搬动不超过M的礼物重量. 思路:看似背包,但M太大.所以要用DFS,但n也有45,所以考虑双向DFS先搜前半部分满足情况的所有重量,然后去重 ...
- poj 1198 hdu 1401 搜索+剪枝 Solitaire
写到一半才发现能够用双向搜索4层来写,但已经不愿意改了,干脆暴搜+剪枝水过去算了. 想到一个非常水的剪枝,h函数为 当前点到终点4个点的最短距离加起来除以2.由于最多一步走2格,然后在HDU上T了, ...
随机推荐
- Editplus注册码生成代码
function generate_editplus_regcode(username) { var list = [0,49345,49537,320,49921,960,640,49729,506 ...
- Android的SQLite基本操作
涉及SQLite的增删改查,结果用log显示 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ...
- QTableWidgetItem QTreeWidgwtItem 复选框的取消显示方法
思路: QTableWidgetItem :item->setData(Qt::CheckStateRole,QVariant()); QTreeWidgwtItem :item-> ...
- php的if函数
条件语句用于基于不同条件执行不同的动作 PHP 条件语句 在您编写代码时,经常会希望为不同的决定执行不同的动作.您可以在代码中使用条件语句来实现这一点. 在 PHP 中,我们可以使用以下条件语句: i ...
- C++入门经典-例3.5-判断某一年是否是闰年之嵌套判断
1:代码如下: // 3.5.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <iostream> using ...
- Springboot2.x使用redis作为缓存
一.Springboot2.x关于配置redis作为缓存. 基本配置如下: (1)在application.properties文件中 spring.redis.database=2 //第几个数据库 ...
- MyEclipse下复制的web项目
MyEclipse下复制的web项目,需要修改MyEclipse->Project Facets->Web
- Dart 基本语法
?? // 如果b为null则赋值,否则保持原样 b ??= value; 级联符号.. querySelector('#confirm') // Get an object. ..text = 'C ...
- 远程连接elasticsearch遇到的问题
本文转自:https://blog.csdn.net/xuchuangqi/article/details/78989940 1.首先要远程连接就要把配置文件的network.host: 改为 net ...
- Wireshark 学习笔记 Lebal:Research
学习Wireshark主要是为了契合我最近做的线性激光雷达项目,主要用于抓取数据包 首先是三本书比较值得一看,第一本是清华大学出版社的,侧重教学,第二三两本是人民邮电出版社的,其中第二本是许多课程的指 ...