• Eight HDU


    记得上人工智能课的时候老师讲过一个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;
    }
  • 相关阅读:
    680. Valid Palindrome II【easy】
    125. Valid Palindrome【easy】
    459. Repeated Substring Pattern【easy】
    2. Trailing Zeros【easy】
    142. O(1) Check Power of 2【easy】
    181. Flip Bits【easy】
    183.Wood Cut【hard】
    61. Search for a Range【medium】
    关闭微软对win10的推送
    让未激活的win8.1不再跳出提示激活的窗口
  • 原文地址:https://www.cnblogs.com/Accepting/p/12704367.html
Copyright © 2020-2023  润新知