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. sublime text 编辑器的操作

    我一直在用的代码编辑器是sublime text,然后总结了一些相关的操作方法. 一 环境操作 1.放大显示比例:Ctrl+ 2.缩小显示比例:Ctrl- 3.分屏:Alt+ Shift +数字    ...

  2. 10、堆叠窗口StackedWidget

    新建项目,基类选择QMainWindow,勾选ui 堆叠窗口有三个page,每个page有个label   button处,快捷菜单,转到槽,添加代码 void MainWindow::on_push ...

  3. 计算机网络(九),HTTP简介

    目录 1.超文本传输协议HTTP的主要特点 2.HTTP请求结构 3.HTTP响应结构 4.http请求/响应的步骤 九.HTTP简介 1.超文本传输协议HTTP的主要特点 (1)支持客户/服务器模式 ...

  4. Confluence 6 预览一个文件

    当你浏览一个页面的时候,单击一个图片,文件缩略图或者链接将会运行预览. 预览视图包括了从远程 Web 页面导入的图片文件和已经附加到页面中的文件(尽管有可能这些文件没有在页面中显示). 在预览中你可以 ...

  5. ubuntu下jps命令无效

    jps命令无效 #启动zookeeper $ sudo ./zkServer.sh start [sudo] jjboom 的密码: ZooKeeper JMX enabled by default ...

  6. java从ldap中导出数据到ldif文件中

    原创:http://www.cnblogs.com/dqcer/p/7814034.html 导入ldap.jar包,笔者已对下面两个文件测试并通过.若有疑问欢迎留言 LDAPExport.java ...

  7. hive 分组排序函数 row_number() over(partition by " " order by " "desc

    语法:row_number() over (partition by 字段a order by 计算项b desc ) rank --这里rank是别名 partition by:类似hive的建表, ...

  8. 分布式-信息方式-ActiveMQ的Destination高级特性1

    ActiveMQ的Destination高级特性 Destination高级特性----->Composite Destinations 组合队列Composite Destinations : ...

  9. mongo 生命周期

    监听MongoDB的生命周期,只需重写org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener的子类 ...

  10. docker—数据卷

    启动一个数据容器并挂载本地目录 docker run -itd --name=volume /opt/volume:/tmp/volume --privileged docker.io/nginx-t ...