洛谷P5507 机关(A*)
不会写双向BFS的,死也不会写的
考虑IDA*。一个很naive的h函数是:每个按钮到目标的距离的最大值。于是你花20min就可以拿到40分:
#include<cstdio> short s[15],a[15][5],maxd=0,opt[20]; inline bool check(){ for(short i=1;i<=12;++i)if(s[i]!=1)return 0; return 1; } inline short h(){ short i,maxn=0; for(i=1;i<=12;++i)if(s[i]!=1&&5-s[i]>maxn)maxn=5-s[i]; return maxn; } bool dfs(int d){ if(d+h()>maxd)return 0; if(check())return 1; short i,t1,t2,p; for(i=1;i<=12;++i){ t1=s[i];p=a[i][s[i]];t2=s[p]; s[i]=(s[i]&3)+1;s[p]=(s[p]&3)+1; opt[d]=i; if(dfs(d+1))return 1; s[p]=t2;s[i]=t1; //倒过来主要是为了p==i的情况 } return 0; } int main(){ short i,j; for(i=1;i<=12;++i){ scanf("%d",s+i); for(j=1;j<=4;++j)scanf("%d",&a[i][j]); } for(maxd=0;maxd<18;++maxd)if(dfs(0))break; printf("%d\n",maxd); for(i=0;i<maxd;++i)printf("%d ",opt[i]); return 0; }
然而,我们发现这个h函数相当不精确,因为每次最多修改两个按钮,稍加思考可以得到一个更精确的h:每个按钮到目标的距离的和的一半。事实证明这个下界相当紧,把上面代码中的h()换成如下代码即可获得80分:
inline short h(){ short i,sum=0; for(i=1;i<=12;++i)if(s[i]!=1)sum+=5-s[i]; return sum>>1; }
那么剩下20分怎么拿呢?BFS:真香!没关系,IDA*被卡了,我们还有A*!难写多了
#include<cstdio> #include<cstring> #include<queue> using namespace std; int pre[1<<24]; short a[15][5],d[1<<24],opt[1<<24],st[20],sl=-1; struct node{ int x; short g; //g内保存的是A*中的f()与h()的和 node(){} node(int x):x(x){ g=0; for(short i=0;i<24;i+=2)if(x&(3<<i))g+=4-((x>>i)&3); g=(g>>1)+d[x]; } inline bool operator <(const node &b)const{return g>b.g;} }; priority_queue<node> Q; inline short nxt(short x){return (x+1)&3;} int main(){ short i,j,s,t1,t2,p; int h,t=0; bool ok=0; for(i=0;i<12;++i){ scanf("%d",&s); t|=s-1<<(i<<1); for(j=0;j<4;++j){scanf("%d",&a[i][j]);--a[i][j];} } memset(d,0x3f,sizeof(d));d[t]=0; Q.push(node(t)); while(!Q.empty()&&!ok){ h=Q.top().x;Q.pop(); for(i=0;i<12;++i){ t1=(h>>(i<<1))&3;p=a[i][t1];t=h^(t1<<(i<<1))^(nxt(t1)<<(i<<1)); t2=(h>>(p<<1))&3;t^=(t2<<(p<<1))^(nxt(t2)<<(p<<1)); //解码+产生新状态 if(d[t]==0x3f3f){ //A*保证第一次碰到就是最优解 d[t]=d[h]+1; pre[t]=h; opt[t]=i+1; if(!t){ok=1;break;} Q.push(node(t)); } } } printf("%d\n",d[0]); while(pre[t]){ st[++sl]=opt[t]; t=pre[t]; } while(sl>=0)printf("%d ",st[sl--]); return 0; }
A*好像吊打BFS