万圣节后的早晨&&九数码游戏——双向广搜
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; }
九数码游戏
(由于顺时针转,变化太大,估价函数也不好设计。)
(当然这个题可以直接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; }
以上是关于万圣节后的早晨&&九数码游戏——双向广搜的主要内容,如果未能解决你的问题,请参考以下文章
LUA Festival——万圣节&秋收感恩,不一样的万圣节,怪好玩的!
Unity 游戏框架搭建 2019 (九~十二) 第一章小结&第二章简介&第八个示例
《安富莱嵌入式周报》第305期:超级震撼数码管瀑布,使用OpenAI生成单片机游戏代码的可玩性,120通道逻辑分析仪,复古电子设计,各种运动轨迹函数源码实现