万圣节后的早晨&&九数码游戏——双向广搜

Posted miracevin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了万圣节后的早晨&&九数码游戏——双向广搜相关的知识,希望对你有一定的参考价值。

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

 

以上是关于万圣节后的早晨&&九数码游戏——双向广搜的主要内容,如果未能解决你的问题,请参考以下文章

LUA Festival——万圣节&秋收感恩,不一样的万圣节,怪好玩的!

Unity 游戏框架搭建 2019 (九~十二) 第一章小结&第二章简介&第八个示例

《安富莱嵌入式周报》第305期:超级震撼数码管瀑布,使用OpenAI生成单片机游戏代码的可玩性,120通道逻辑分析仪,复古电子设计,各种运动轨迹函数源码实现

洛谷 P1379 八数码难题 Label:判重&&bfs

用VB程序怎么做九九乘法表?

小程序九:导航&地图&画布