记得上人工智能课的时候老师讲过一个A*算法,计算估价函数(f[n]=h[n]+g[n])什么的,感觉不是很好理解,百度上好多都是用逆向BFS写的,我理解的逆向BFS应该是从终点状态出发,然后把每一种状态打表列举出来,最后O(1)查询就可以了。这种办法确实挺好,但是不会....。

这位大佬用的双向BFS https://blog.csdn.net/qq_41670466/article/details/84110090,挺好理解的,但是注释什么的比较少,也没有过多的介绍思路,所以我想借助这篇blog简单的介绍一下这个题目的双向BFS的思路。

双向BFS就是终点状态(从后向前)和起始状态(从前向后)一起寻找,当且仅当而且碰头时,就是答案了。

针对本题来说,初始状态就是输入的转态,终点状态都是一样的123456780(x用0来代替),但是这个状态怎么表示呢?康托展开 (不会的可以点开看一下)。状态表示解决完了,接下来我们看一下转态转移。

当x处在0 3 6这三个位置时,不可以向左移动,当x处于2 5 8这三个位置时,不可以向右移动,当x处于0 1 2这三个位置时,不可以向上移动,处于6 7 8这三个位置时,不可以向下移动。 对于本题样例,s[]=2 3 4 1 5 x 7 6 8。,x是处于5这个位置,如果向上移动,就可以看成s[5]和s[5-3]交换了一下,向下移动可以看成s[5]和s[5+3]交换了一下,

向左s[5]和s[5-1]向右同理....这样就实现了状态之间的转移。

路径的记录。维护两个数组char 和int ,char 用来记录向哪移动了,int 用来记录上一个状态的下标。

最后还要加一个特判,问题是否有解跟逆序对有关,如果逆序对是奇数就有解,否则就无解具体为什么跟线性代数有关吧~~我也不太懂(待解释)。

具体实现都在code中了....

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+;
string a;
int ha[]={,,,,,,,,};//从8到0对应的阶乘
int vis[maxn],vis2[maxn];
struct node {
int num;
char ch;
}pre[maxn];//write path
struct stu {
string s;//当前串
int num;//x的位置
}e;//save now state
int direction[]={-,,-,};//udlr
string s1="udlr",s2="durl";
int ct(string s){//当前串对应的康托值
int sum=;
for(int i=;i<;i++){
int k=;
for(int j=i+;j<;j++){
if(s[j]<s[i]) k++;
}
sum+=k*ha[i];
}
return sum;
}
void writhpath(int x){
if(pre[x].num==-) return ;
writhpath(pre[x].num);
printf("%c",pre[x].ch);
}
void bfs(){
queue<stu> que1,que2;
int q=ct(e.s);
vis[q]=;
stu f,g;
f.s="";
f.num=;
int p=ct(f.s);
vis2[p]=;
pre[].num=-;pre[].num=-; int num=;
que1.push(e);que2.push(f);
while(que1.size()&&que2.size()){
f=que1.front();que1.pop();
p=ct(f.s);
if(vis2[p]){
writhpath(vis[p]);
int k=vis2[p];
while(pre[k].num!=-) {
printf("%c",pre[k].ch);
k=pre[k].num;
}
cout<<endl;
return ;
}
else{
for(int i=;i<;i++){
if(i==&&f.num<) continue ;
if(i==&&f.num>) continue ;
if(i==&&f.num%==) continue ;
if(i==&&f.num%==) continue ;
int dx=f.num+direction[i];g=f;
swap(g.s[f.num],g.s[dx]);
q=ct(g.s);
if(vis[q]) continue ;
vis[q]=++num;g.num=dx;
que1.push(g);
pre[num].num=vis[p];pre[num].ch=s1[i];
}
}
f=que2.front();que2.pop();
p=ct(f.s);
if(vis[p]){
writhpath(vis[p]);
int k=vis2[p];
while(pre[k].num!=-) {
printf("%c",pre[k].ch);
k=pre[k].num;
}
cout<<endl;
return ;
}
else{
for(int i=;i<;i++){
if(i==&&f.num<) continue ;
if(i==&&f.num>) continue ;
if(i==&&f.num%==) continue ;
if(i==&&f.num%==) continue ;
int dx=f.num+direction[i];g=f;
swap(g.s[f.num],g.s[dx]);
q=ct(g.s);
if(vis2[q]) continue ;
vis2[q]=++num;g.num=dx;
que2.push(g);
pre[num].num=vis2[p];pre[num].ch=s2[i];
}
}
}
puts("unsolvable");
}
int main(){
while(getline(cin,a)){
string c="";
int n=a.size(),pos=,j=;
for(int i=;i<n;i++){
if(a[i]==' ') continue ;
if(a[i]=='x'){
c+='';pos=j;
}
else {
c+=a[i];j++;
}
}
int k=;e.num=pos;e.s=c;
for (int i=;i<;i++){
if (e.s[i]=='')continue;
for (int j = ;j<i;j++){
if (e.s[j] == '')continue;
if (e.s[j]>e.s[i])k++;
}
}
if(k&) {
puts("unsolvable");
}
else {
memset(vis,,sizeof vis);
memset(vis2,,sizeof vis2);
bfs();
}
}
return ;
}

Eight HDU - 1043 (双向BFS)的更多相关文章

  1. HDU - 3085 双向BFS + 技巧处理 [kuangbin带你飞]专题二

    题意:有两只鬼,一个男孩女孩被困在迷宫中,男孩每秒可以走三步,女孩只能1步,鬼可以两步且可以通过墙.问男孩女孩是否可以在鬼抓住他们之前会合? 注意:每秒开始鬼先移动,然后两人开始移动. 思路:以男孩和 ...

  2. hdu 3085(双向bfs)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3085 思路:双向广搜,每次从M出发,搜三步,从G出发,搜一步,然后就是判断是否走到对方已经走过的格子, ...

  3. HDU 1043 Eight BFS

    题意:就是恢复成1,2,3,4,5,6,7,8,0; 分析:暴力BFS预处理,所有路径,用康拓展开判重,O(1)打印 93ms 还是很快的 #include <iostream> #inc ...

  4. HDU 1043 Eight (BFS&#183;八数码&#183;康托展开)

    题意  输出八数码问题从给定状态到12345678x的路径 用康托展开将排列相应为整数  即这个排列在全部排列中的字典序  然后就是基础的BFS了 #include <bits/stdc++.h ...

  5. HDU 1043 Eight(双向BFS+康托展开)

    http://acm.hdu.edu.cn/showproblem.php?pid=1043 题意:给出一个八数码,求出到达指定状态的路径. 思路:路径寻找问题.在这道题里用到的知识点挺多的.第一次用 ...

  6. Eight (HDU - 1043|POJ - 1077)(A* | 双向bfs+康拓展开)

    The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've see ...

  7. hdu 1043 Eight(双向bfs)

    题意:经典八数码问题 思路:双向bfs ps:还有a*算法(还不会)等解法. 代码: #include<iostream> #include<stdio.h> #include ...

  8. HDU 3085 Nightmare II 双向bfs 难度:2

    http://acm.hdu.edu.cn/showproblem.php?pid=3085 出的很好的双向bfs,卡时间,普通的bfs会超时 题意方面: 1. 可停留 2. ghost无视墙壁 3. ...

  9. 2017多校第10场 HDU 6171 Admiral 双向BFS或者A*搜索

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6171 题意: 给你一个高度为6的塔形数组,你每次只能将0与他上下相邻的某个数交换,问最少交换多少次可以 ...

随机推荐

  1. [ex-kmp] HDU 2019 Multi-University Training Contest 5-string matching

    string matching Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others ...

  2. Redis系列(一):小试牛刀

    引言 随着互联网的高速发展,传统的关系数据库(如MySQL.Microsoft SQL Server等)已不能满足日益增长的业务需求,如商品秒杀.抢购等及时性非常强的功能,随着应用高并发的访问,会造成 ...

  3. OpenCV-Python 使用OCR手写数据集运行KNN | 五十四

    目标 在本章中 我们将使用我们在kNN上的知识来构建基本的OCR应用程序. 我们将尝试使用OpenCV自带的数字和字母数据集. 手写数字的OCR 我们的目标是构建一个可以读取手写数字的应用程序.为此, ...

  4. Android | 教你如何用华为HMS MLKit SDK 三十分钟在安卓上开发一个微笑抓拍神器

    Android | 只要三十分钟就可以在手机上开发一个微笑抓拍神器!!! 前言 前段时间Richard Yu在发布会上给大家介绍了华为HMS Core4.0,回顾发布会信息请戳: 华为面向全球发布HM ...

  5. SuperMap许可常见问题及解决办法

    一.试用许可申请可以直接在北京超图软件股份有限公司官网的“SuperMap 技术资源中心”申请试用许可,申请后您将获得:1.如果申请的是 SuperMap GIS 7C 系列产品的许可,您将获得 一个 ...

  6. 【LeetCode】141.环形链表

    题目描述 141.环形链表 给定一个链表,判断链表中是否有环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 -1,则在该链表中 ...

  7. python数据库MySQL之视图,触发器,事务,存储过程,函数

    一 视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,可以将该结果集当做表来使用. 使用视图我们可以把查询过程中的 ...

  8. 还不懂 ConcurrentHashMap ?这份源码分析了解一下

    上一篇文章介绍了 HashMap 源码,反响不错,也有很多同学发表了自己的观点,这次又来了,这次是 ConcurrentHashMap 了,作为线程安全的HashMap ,它的使用频率也是很高.那么它 ...

  9. 【WPF学习】第六十五章 创建无外观控件

    用户控件的目标是提供增补控件模板的设计表面,提供一种定义控件的快速方法,代价是失去了将来的灵活性.如果喜欢用户控件的功能,但需要修改使其可视化外观,使用这种方法就有问题了.例如,设想希望使用相同的颜色 ...

  10. es6声明一个类

    js语言的传统方式是通过定义构造函数,生成心得对象.是一种基于原型的面向对象系统.在es6中增加了class类的概念,可以使用class关键字来声明一个类.之后用这个类来实例化对象. 构造函数示例 c ...