1. 程式人生 > >萬聖節後的早晨&&九數碼遊戲——雙向廣搜

萬聖節後的早晨&&九數碼遊戲——雙向廣搜

name break 數組 node 2個 type div 元素 分享圖片

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==\n)break; for(int i=1;i<=n;i++){ int lp=0; while((s[lp]=getchar())||23333) if(s[lp++]==\n)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\n",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

萬聖節後的早晨&&九數碼遊戲——雙向廣搜