zoukankan      html  css  js  c++  java
  • 万圣节后的早晨&&九数码游戏——双向广搜

    https://www.luogu.org/problemnew/show/P1778

    https://www.luogu.org/problemnew/show/P2578

    双向广搜。

    有固定起点终点,过程可逆。

    有时用于A*估价函数不好用的时候。

    万圣节后的早晨

    (由于鬼可以同时移动,估价函数不好设计)

    优化:

    1.预处理。

    预处理每个可以到的位置的上下左右的块能否到达,建一个类似前向星的数组。

    就可以很快地查询了。

    2.每次枚举前1/2个鬼就可以判定当前的状态是否合法,可以减掉不少。

    尽可能提前判断合法性,越快越好。

    代码:

    #include<bits/stdc++.h>
    #define ri register int 
    using namespace std;
    typedef long long ll;
    const int N=26;
    const int M=205;
    const int P=258;
    int mp[N][N];
    int d1[M][M][M];
    int d2[M][M][M];
    int id[N][N];
    int to[M][6],sz[M];
    int tot;
    int n,m,k;
    char s[N];
    struct node{
        int mem[4];
        void clear(){
            mem[0]=mem[1]=mem[2]=mem[3]=0;
        }
        void op(){
            cout<<mem[1]<<" "<<mem[2]<<" "<<mem[3]<<endl;
        }
    }st,nd;
    node unzip(ll x){
        //cout<<" unzip "<<x<<endl;
        node ret;
        ret.clear();
        int cnt=0;
        while(x){
            cnt++;
            ret.mem[cnt]=x%P;
            x/=P;
        }
        return ret;
    }
    int mv[5][2]={{0,0},{+1,0},{-1,0},{0,+1},{0,-1}};
    int zip(node lp){
        return lp.mem[3]*P*P+lp.mem[2]*P+lp.mem[1];
    }
    queue<pair<int,int> >q1;
    queue<pair<int,int> >q2;
    bool bfs1(int dep){
        while(!q1.empty()){
            pair<int,int>now=q1.front();
            if(now.second==dep) return false;
            q1.pop();
            //cout<<" haha "<<endl;
            node kk=unzip(now.first);
            //if(dep<10) kk.op();
            node lp;lp.clear();
            for(int i=1;i<=sz[kk.mem[1]];i++){
                lp.mem[1]=to[kk.mem[1]][i];
                
                for(int j=1;j<=sz[kk.mem[2]];j++){
                    lp.mem[2]=to[kk.mem[2]][j];
                    if(lp.mem[1]==lp.mem[2]) continue;
                    if(lp.mem[1]==kk.mem[2]&&lp.mem[2]==kk.mem[1]) continue;
                    //cout<<"lp "<<endl;lp.op();
                    for(int p=1;p<=sz[kk.mem[3]];p++){
                        lp.mem[3]=to[kk.mem[3]][p];
                        if(lp.mem[3]){
                            if(lp.mem[3]==lp.mem[2]) continue;
                            if(lp.mem[3]==lp.mem[1]) continue;
                            if(lp.mem[3]==kk.mem[2]&&lp.mem[2]==kk.mem[3]) continue;
                            if(lp.mem[3]==kk.mem[1]&&lp.mem[1]==kk.mem[3]) continue;
                        }
                        if(d2[lp.mem[1]][lp.mem[2]][lp.mem[3]]!=-1) return true;
                        else if(d1[lp.mem[1]][lp.mem[2]][lp.mem[3]]==-1){
                            d1[lp.mem[1]][lp.mem[2]][lp.mem[3]]=dep;
                            q1.push(make_pair(zip(lp),now.second+1));
                        }
                    }
                }
            }
        }
        return false;
    }
    bool bfs2(int dep){
        while(!q2.empty()){
            pair<int,int>now=q2.front();
            if(now.second==dep) return false;
            q2.pop();
            node kk=unzip(now.first);
            node lp;lp.clear();
            for(int i=1;i<=sz[kk.mem[1]];i++){
                lp.mem[1]=to[kk.mem[1]][i];
                for(int j=1;j<=sz[kk.mem[2]];j++){
                    lp.mem[2]=to[kk.mem[2]][j];
                    if(lp.mem[1]==lp.mem[2]) continue;
                    if(lp.mem[1]==kk.mem[2]&&lp.mem[2]==kk.mem[1]) continue;
                    for(int p=1;p<=sz[kk.mem[3]];p++){
                        lp.mem[3]=to[kk.mem[3]][p];
                        if(lp.mem[3]){
                            if(lp.mem[3]==lp.mem[2]) continue;
                            if(lp.mem[3]==lp.mem[1]) continue;
                            if(lp.mem[3]==kk.mem[2]&&lp.mem[2]==kk.mem[3]) continue;
                            if(lp.mem[3]==kk.mem[1]&&lp.mem[1]==kk.mem[3]) continue;
                        }
                        if(d1[lp.mem[1]][lp.mem[2]][lp.mem[3]]!=-1) return true;
                        else if(d2[lp.mem[1]][lp.mem[2]][lp.mem[3]]==-1){
                            d2[lp.mem[1]][lp.mem[2]][lp.mem[3]]=dep;
                            q2.push(make_pair(zip(lp),now.second+1));
                        }
                    }
                }
            }
        }
        return false;
    }
    void clear(){
        tot=0;
        memset(mp,0,sizeof mp);
        memset(d1,-1,sizeof d1);
        memset(d2,-1,sizeof d2);
        memset(id,0,sizeof id);
        memset(to,0,sizeof to);
        memset(sz,0,sizeof sz);
        st.clear();
        nd.clear();
        while(!q1.empty())q1.pop();
        while(!q2.empty())q2.pop();
    }
    int main(){
        while(1){
            cin>>m>>n>>k;
            if(n==0&&m==0&&k==0) break;
            clear();
            char ch;while((ch=getchar())||23333)if(ch=='
    ')break;
            for(int i=1;i<=n;i++){
                int lp=0;
                while((s[lp]=getchar())||23333) if(s[lp++]=='
    ')break;
                for(int j=1;j<=m;j++){
                    if(s[j-1]==' '){
                        mp[i][j]=0;
                        id[i][j]=++tot;
                    }
                    else if(s[j-1]=='#'){
                        mp[i][j]=1;
                    }
                    else if(s[j-1]>='a'&&s[j-1]<='z'){
                        id[i][j]=++tot;
                        st.mem[s[j-1]-'a'+1]=tot;
                    }
                    else if(s[j-1]>='A'&&s[j-1]<='Z'){
                        id[i][j]=++tot;
                        nd.mem[s[j-1]-'A'+1]=tot;
                    }
                }
            }
           
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    if(!id[i][j]) continue;
                    //cout<<i<<" "<<j<<endl;
                    for(int p=0;p<5;p++){
                        int dx=i+mv[p][0];
                        int dy=j+mv[p][1];
                        if(dx<1||dx>n) continue;
                        if(dy<1||dy>m) continue;
                        if(mp[dx][dy]) continue;
                        sz[id[i][j]]++;
                        to[id[i][j]][sz[id[i][j]]]=id[dx][dy];
                    }
                }
            } //cout<<"after "<<endl;
            id[0][0]=0;
            sz[0]++;
            to[0][1]=0;
            //st.op();
            q1.push(make_pair(zip(st),0));
            //cout<<zip(st)<<endl;
            d1[st.mem[1]][st.mem[2]][st.mem[3]]=0;
            q2.push(make_pair(zip(nd),0));
            d2[nd.mem[1]][nd.mem[2]][nd.mem[3]]=0;
            int ans=0;
            int b1=0,b2=0;
            while(1){
                ans++;
                //if(ans<10) cout<<ans<<endl;
                if(bfs1(++b1)) break;
                ans++;
                if(bfs2(++b2)) break;    
            }
            cout<<ans<<endl;
        }
        return 0;
    }
    View Code

    九数码游戏

    (由于顺时针转,变化太大,估价函数也不好设计。)

    (当然这个题可以直接bfs,但是双向广搜在luogu上快了50倍)其实要注意的就是一点。

    因为双向广搜的另一边是一个逆过程,所以,顺时针变成逆时针,向右变成向左。

    值得注意。

    至于方案,根据hash表中元素的单一性,而且有SPJ,所以,记录一下每个状态的前驱即可。

    代码:

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=10;
    const int M=362990;
    const int mo=1e5;
    const int ED=12345678;
    struct ha{
        int val[M];
        int nxt[M],hd[mo];
        int pre[M];
        int cnt;
        void ins(int x,int from){
            cnt++;
            val[cnt]=x;pre[cnt]=from;
            int pos=x%mo;
            nxt[cnt]=hd[pos];
            hd[pos]=cnt;
        }
        bool query(int x){
            int pos=x%mo;
            for(int i=hd[pos];i;i=nxt[i]){
                if(val[i]==x) return 1;
            }
            return 0;
        }
        int fin(int x){
            int pos=x%mo;
            for(int i=hd[pos];i;i=nxt[i]){
                if(val[i]==x) return pre[i];
            }
            return 0;
        }
    }HA1,HA2;
    queue<pair<int,int> >q1;
    queue<pair<int,int> >q2;
    int st,nd;
    int sta[1005],top;
    int num1,num2;
    int mp[4][4];
    void op(int x){
        for(int i=3;i>=1;i--)
            for(int j=3;j>=1;j--)
                mp[i][j]=x%10,x/=10;
        for(int i=1;i<=3;i++){
            for(int j=1;j<=3;j++){
                printf("%d ",mp[i][j]);
            }puts("");
        }
        puts("");
    }
    int mv1(int x){
        for(int i=3;i>=1;i--)
            for(int j=3;j>=1;j--)
                mp[i][j]=x%10,x/=10;
        int tmp=mp[1][1];
        mp[1][1]=mp[2][1];mp[2][1]=mp[3][1];mp[3][1]=mp[3][2];mp[3][2]=mp[3][3];
        mp[3][3]=mp[2][3];mp[2][3]=mp[1][3];mp[1][3]=mp[1][2];mp[1][2]=tmp;
        int ret=0;
        for(int i=1;i<=3;i++){
            for(int j=1;j<=3;j++){
                ret=ret*10+mp[i][j];
            }
        }return ret;
    }
    int mv2(int x){
        for(int i=3;i>=1;i--)
            for(int j=3;j>=1;j--)
                mp[i][j]=x%10,x/=10;
        int tmp=mp[2][3];
        mp[2][3]=mp[2][2];mp[2][2]=mp[2][1];mp[2][1]=tmp;
        int ret=0;
        for(int i=1;i<=3;i++){
            for(int j=1;j<=3;j++){
                ret=ret*10+mp[i][j];
            }
        }return ret;
    }
    int mv3(int x){
        for(int i=3;i>=1;i--)
            for(int j=3;j>=1;j--)
                mp[i][j]=x%10,x/=10;
        int tmp=mp[1][1];
        mp[1][1]=mp[1][2];mp[1][2]=mp[1][3];mp[1][3]=mp[2][3];mp[2][3]=mp[3][3];
        mp[3][3]=mp[3][2];mp[3][2]=mp[3][1];mp[3][1]=mp[2][1];mp[2][1]=tmp;
        int ret=0;
        for(int i=1;i<=3;i++){
            for(int j=1;j<=3;j++){
                ret=ret*10+mp[i][j];
            }
        }return ret;
    }
    int mv4(int x){
        for(int i=3;i>=1;i--)
            for(int j=3;j>=1;j--)
                mp[i][j]=x%10,x/=10;
        int tmp=mp[2][1];
        mp[2][1]=mp[2][2];mp[2][2]=mp[2][3];mp[2][3]=tmp;
        int ret=0;
        for(int i=1;i<=3;i++){
            for(int j=1;j<=3;j++){
                ret=ret*10+mp[i][j];
            }
        }return ret;
    }
    int bfs1(int dp){
        while(!q1.empty()){
            pair<int,int> lp=q1.front();
            if(lp.second==dp) return 0;
            q1.pop();
            int now=lp.first;
            int t1=mv1(now);
            if(HA2.query(t1)){
                num1=now;
                num2=t1;
                return 1;
            }
            else if(!HA1.query(t1)){
                HA1.ins(t1,now);
                q1.push(make_pair(t1,lp.second+1));
            }
            
            int t2=mv2(now);
            if(HA2.query(t2)){
                num1=now;
                num2=t2;
                return 1;
            }
            else if(!HA1.query(t2)){
                HA1.ins(t2,now);
                q1.push(make_pair(t2,lp.second+1));
            }
        }
        return 2;
    }
    int bfs2(int dp){
        while(!q2.empty()){
            pair<int,int> lp=q2.front();
            if(lp.second==dp) return 0;
            q2.pop();
            int now=lp.first;
            int t1=mv3(now);
            if(HA1.query(t1)){
                num2=now;
                num1=t1;
                return 1;
            }
            else if(!HA2.query(t1)){
                HA2.ins(t1,now);
                q2.push(make_pair(t1,lp.second+1));
            }
            
            int t2=mv4(now);
            if(HA1.query(t2)){
                num2=now;
                num1=t2;
                return 1;
            }
            else if(!HA2.query(t2)){
                HA2.ins(t2,now);
                q2.push(make_pair(t2,lp.second+1));
            }
        }
        return 2;
    }
    int main(){
        int t;
        for(int i=1;i<=9;i++)scanf("%d",&t),st=st*10+t;
        nd=ED;
        if(st==nd){
            printf("0");
            op(st);
        }
        HA2.ins(nd,0);
        HA1.ins(st,0);
        q1.push(make_pair(st,0));
        q2.push(make_pair(nd,0));
        int ans=0;
        int b1=0,b2=0;
        while(1){
            ans++;
            int d1=bfs1(++b1);
            if(d1==1) break;
            ans++;
            int d2=bfs2(++b2);
            if(d2==1) break;
            if(d1==2&&d2==2) {
                printf("UNSOLVABLE");return 0;
            }
        }
        //over
        printf("%d
    ",ans);
        top=0;
        while(num1!=0){
            sta[++top]=num1;
            num1=HA1.fin(num1);
        }
        while(top)op(sta[top--]);
        while(num2!=0){
            op(num2);
            num2=HA2.fin(num2);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Dom探索之基础详解
    PS切图(一)
    软件工程课程建议
    【一周读书】一点营养学笔记
    【一周读书】自卑与超越
    【一周读书】先教育好自己,再谈教导孩子
    【一周读书】学习如何学习
    【一周读书】你的理想
    结对项目编程
    Day4——提权学习之MySQL数据库(启动项提权)
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9780215.html
Copyright © 2011-2022 走看看