Eight HDU - 1043 (双向BFS)

记得上人工智能课的时候老师讲过一个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+7;
string a;
int ha[10]={40320,5040,720,120,24,6,2,1,1};//从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[]={-3,3,-1,1};//udlr
string s1="udlr",s2="durl";
int ct(string s){//当前串对应的康托值
    int sum=0;
    for(int i=0;i<9;i++){
        int k=0;
        for(int j=i+1;j<9;j++){
            if(s[j]>s[i]) k++;
        }
        sum+=k*ha[i];
    }
    return sum;
}
void writhpath(int x){
    if(pre[x].num==-1) return ;
    writhpath(pre[x].num);
    printf("%c",pre[x].ch);
}
void bfs(){
    queue<stu> que1,que2;
    int q=ct(e.s);
    vis[q]=1;
    stu f,g;
    f.s="123456780";
    f.num=8;
    int p=ct(f.s);
    vis2[p]=2;
    pre[1].num=-1;pre[2].num=-1;

    int num=2;
    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!=-1) {
                printf("%c",pre[k].ch);
                k=pre[k].num;
            }
            cout<<endl;
            return ;
        }
        else{
            for(int i=0;i<4;i++){
               if(i==0&&f.num<3) continue ;
               if(i==1&&f.num>5) continue ;
               if(i==2&&f.num%3==0) continue ;
               if(i==3&&f.num%3==2) 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!=-1) {
                printf("%c",pre[k].ch);
                k=pre[k].num;
           }
           cout<<endl;
           return ;
        }
        else{
            for(int i=0;i<4;i++){
               if(i==0&&f.num<3) continue ;
               if(i==1&&f.num>5) continue ;
               if(i==2&&f.num%3==0) continue ;
               if(i==3&&f.num%3==2) 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=0,j=0;
        for(int i=0;i<n;i++){
            if(a[i]==‘ ‘) continue ;
            if(a[i]==‘x‘){
                c+=‘0‘;pos=j;
            }
            else {
                c+=a[i];j++;
            }
        }
        int k=0;e.num=pos;e.s=c;
        for (int i=0;i<9;i++){
            if (e.s[i]==‘0‘)continue;
                for (int j = 0;j<i;j++){
                    if (e.s[j] == ‘0‘)continue;
                    if (e.s[j]>e.s[i])k++;
            }
        }
        if(k&1) {
             puts("unsolvable");
        }
        else {
            memset(vis,0,sizeof vis);
            memset(vis2,0,sizeof vis2);
            bfs();
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Accepting/p/12704367.html

时间: 2024-10-11 18:24:39

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

HDU 1043 Eight BFS

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

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

题意  输出八数码问题从给定状态到12345678x的路径 用康托展开将排列对应为整数  即这个排列在所有排列中的字典序  然后就是基础的BFS了 #include <bits/stdc++.h> using namespace std; const int N = 5e5, M = 9; int x[4] = { -1, 1, 0, 0}; int y[4] = {0, 0, -1, 1}; int fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320

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

http://acm.hdu.edu.cn/showproblem.php?pid=1043 题意:给出一个八数码,求出到达指定状态的路径. 思路:路径寻找问题.在这道题里用到的知识点挺多的.第一次用双向BFS来做. ①双向BFS 在单向BFS的基础上,多建一个从终止状态开始搜索的队列,当然这个时候需要两个vis[]辅助数组,分别记录两个队列的访问情况,当两个队列相遇时即可终止循环. ②康托展开 X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[

HDU 1043 Eight八数码解题思路(bfs+hash 打表 IDA* 等)

题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原为初始状态 思路: 参加网站比赛时拿到此题目,因为之前写过八数码问题,心中暗喜,于是写出一套暴力bfs+hash,结果TLE呵呵 思路一:bfs+hash(TLE) 1 #include <cstdio> 2 #include <cstring> 3 #include <queu

HDU 1195 Open the Lock 双向BFS

题目链接:Open the Lock 题意:就是给定两个4位数,起始,结束.问从起始数字到达结束数字 最少变换多少步,每个数 可以+1 / -1 或交换位置,都算做是一步. 单广,双广都用了,感觉双向BFS,太棒了,HDU的这个题双向BFS时间优化的太棒了 有图,有真相! 时间优化了近9倍... PS:今天还学习一个sscanf函数,挺棒的 单搜的代码就不贴了,贴个双搜的 #include<cstdio> #include <iostream> #include<cstrin

HDU 1242 -Rescue (双向BFS)&amp;&amp;( BFS+优先队列)

题目链接:Rescue 进度落下的太多了,哎╮(╯▽╰)╭,渣渣我总是埋怨进度比别人慢...为什么不试着改变一下捏.... 开始以为是水题,想敲一下练手的,后来发现并不是一个简单的搜索题,BFS做肯定出事...后来发现题目里面也有坑 题意是从r到a的最短距离,"."相当时间单位1,"x"相当时间单位2,求最短时间 HDU 搜索课件上说,这题和HDU1010相似,刚开始并没有觉得像剪枝,就改用  双向BFS   0ms  一Y,爽! 网上查了一下,神牛们竟然用BFS+

HDU 1242 -Rescue (双向BFS)&amp;amp;&amp;amp;( BFS+优先队列)

题目链接:Rescue 进度落下的太多了,哎╮(╯▽╰)╭,渣渣我总是埋怨进度比别人慢...为什么不试着改变一下捏.... 開始以为是水题,想敲一下练手的,后来发现并非一个简单的搜索题,BFS做肯定出事...后来发现题目里面也有坑 题意是从r到a的最短距离,"."相当时间单位1,"x"相当时间单位2,求最短时间 HDU 搜索课件上说,这题和HDU1010相似,刚開始并没有认为像剪枝,就改用  双向BFS   0ms  一Y,爽! 网上查了一下,神牛们居然用BFS+优

HDU 1043 POJ 1077 八数码问题

以下内容转载自:http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html 八数码的八境界 研究经典问题,空说不好,我们拿出一个实际的题目来演绎.八数码问题在北大在线测评系统中有一个对应的题,题目描述如下: Eight Time Limit: 1000MS    Memory Limit: 65536K  Special Judge Description The 15-puzzle has been aroundfor ove

HDU1195 双向BFS(或BFS)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1195 , 双向BFS或者直接BFS也可以过. 其实这道题只是单向BFS就可以过的,但是为了练算法,所以还是用了双向BFS来写. 算法: 先预处理一下,从1111到9999的所有点进行构图(由于是1~9的,所以除去含有0元素的数字),能进行一次变换变成的数字则表示两点之间连通.然后从初态与目态两个点进行BFS,如果有轨迹重合的就返回路程和. 这里注意双向BFS要一层一层的进行搜索,不然的话会产生错误,