• P4289 [HAOI2008]移动玩具(bfs)


    P4289 [HAOI2008]移动玩具

    双向bfs+状态压缩+记忆化搜索

    双向bfs用于对bfs的优化,每次找到可扩展节点少的一边进行一次bfs,找到的第一个互相接触的点即为最短路径

    矩阵范围仅4*4大小,我们容易想到用二进制数压缩其状态,利于求解。

    既然转成二进制,大小又<2^17,那么可以再加数组进行记忆化

    不要忘了起点终点相同时的特判qwq

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    using namespace std;
    struct data{int zip,step;};
    int ans,rec1[65538],rec2[65538]; //rec:记忆化用
    queue <data> h[2]; //分别代表从起点/终点开始的bfs队列
    inline void check(int to,int p,data x){ //检查该点是否符合条件
        if(rec1[to]!=-1){ 
            if(rec2[to]!=p) ans=rec1[to]+x.step+1; //如果该点已被对面搜到,那么已经得出最优解
        }else{
            rec1[to]=x.step+1,rec2[to]=p;
            h[p].push((data){to,x.step+1});
        }
    }
    void output(int t){ //检查用,将10进制数转回4*4的二进制矩阵
        cout<<"---
    ";
        int h[19];
        for(int k=t,i=15;i>=0;--i) h[i]=k&1,k>>=1;
        for(int i=0;i<4;++i){
                for(int j=i*4;j<=i*4+3;++j) cout<<h[j];
                cout<<endl;
            }
        cout<<"---
    ";
    }
    inline void bfs(){
        int p=(h[0].size()>h[1].size()),now=(h[p].front()).step; //找到可扩展节点少的一边,并且只扩展一层
        while(!h[p].empty()){
            data x=h[p].front();
            if(x.step!=now||ans) break;
            h[p].pop();
            int k=1,to;
            for(int i=1;i<65536;i<<=1,++k){ //用二进制数表示转移过程
                if(!(x.zip&i)) continue;
                if(k%4!=0&&(!(x.zip&(i<<1)))){ //向左
                    to=x.zip-i+(i<<1);
                    check(to,p,x);
                }
                if(k%4!=1&&(!(x.zip&(i>>1)))){ //向右
                    to=x.zip-i+(i>>1);
                    check(to,p,x);
                }
                if(k>4&&(!(x.zip&(i>>4)))){ //向下
                    to=x.zip-i+(i>>4);
                    check(to,p,x);
                }
                if(k<13&&(!(x.zip&(i<<4)))){ //向上
                    to=x.zip-i+(i<<4);
                    check(to,p,x);
                }
            }
        }
    }
    int main(){
        memset(rec1,-1,sizeof(rec1));
        char q[6]; int tot1=0,tot2=0;
        for(int i=1;i<=4;++i){  //矩阵转成十进制数
            cin>>q;
            for(int j=0;j<=3;++j) tot1+=q[j]-48,tot1<<=1; 
        }tot1>>=1; //注意最后要右移一位
        h[0].push((data){tot1,0}); rec1[tot1]=0; rec2[tot1]=0;
        for(int i=1;i<=4;++i){
            cin>>q;
            for(int j=0;j<=3;++j) tot2+=q[j]-48,tot2<<=1; 
        }tot2>>=1;
        h[1].push((data){tot2,0}); rec1[tot2]=0; rec2[tot2]=1;
        while(!ans&&tot1!=tot2) bfs(); //注意特判
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    用jQuery写的一个简单的弹出窗口(IE7\IE8\FF3)
    live write test
    sql2
    查询所有表索引
    java初学问题记录(2012.02.092012.02.16)
    SQL
    centso7网卡bond
    vmware模板
    Dockerfile参考
    Docker简单介绍
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/9591669.html
Copyright © 2020-2023  润新知