一个舰队的目标状态如上图。红色是旗舰。然后给你初始局面,每一次决策可以把旗舰和其上一层或下一层的两个相邻的进行交换。如果能在20步内出解的话,输出最小步数;否则输出“too difficult”。
把每个方块当成0~5的数,整个状态正好可以压缩成1个21位的6进制数,恰好可以用long long存下,可以用set / 哈希表存储。
定义估价函数f(S)表示局面S的每个格子所在层数与它的目标状态所在层的差的绝对值之和。
这样每一次移动最多使这个值减小2,如果这个值大于(20-已经走的步数)*2,则剪枝。
#include<cstdio> #include<algorithm> #include<queue> #include<set> using namespace std; const int dx[]={1,1,-1,-1},dy[]={0,1,0,-1}; typedef long long ll; typedef pair<int,int> Point; set<ll>S; int T; struct Node{ ll st; Point pos; int d; Node(){} Node(const ll &st,const Point &pos,const int &d){ this->st=st; this->pos=pos; this->d=d; } }; int ceng[25]; int Abs(int x){ return x<0 ? (-x) : x; } int calc(ll x){ int res=0; for(int i=0;i<=20;++i){ res+=Abs((int)(x%6ll)-ceng[i]); x/=6; } return res; } queue<Node>q; int wei[8][8]; ll pw[30]; int main(){ int x; // freopen("1001.in","r",stdin); // freopen("1001.out","w",stdout); pw[0]=1; for(int i=1;i<=20;++i){ pw[i]=pw[i-1]*6ll; } scanf("%d",&T); ceng[0]=ceng[1]=ceng[2]=ceng[3]=ceng[4]=ceng[5]=5; ceng[6]=ceng[7]=ceng[8]=ceng[9]=ceng[10]=4; ceng[11]=ceng[12]=ceng[13]=ceng[14]=3; ceng[15]=ceng[16]=ceng[17]=2; ceng[18]=ceng[19]=1; ceng[20]=0; int pen=20; for(int i=0;i<6;++i){ for(int j=0;j<=i;++j){ wei[i][j]=pen; --pen; } } ll goal=0; for(int i=0;i<6;++i){ for(int j=0;j<=i;++j){ goal=goal*6ll+(ll)i; } } for(;T;--T){ S.clear(); ll st=0; Point stapos; for(int i=0;i<6;++i){ for(int j=0;j<=i;++j){ scanf("%d",&x); if(x==0){ stapos=Point(i,j); } st=st*6ll+(ll)x; } } if(st==goal){ puts("0"); continue; } S.insert(st); bool ok=0; while(!q.empty()){ q.pop(); } q.push(Node(st,stapos,0)); while(!q.empty()){ Node U=q.front(); q.pop(); // ll now=U.st; // for(int i=0;i<6;++i){ // for(int j=0;j<=i;++j){ // printf("%I64d ",now/pw[wei[i][j]]%6ll); // } // puts(""); // } // puts(""); if(U.d>=20){ continue; } for(int i=0;i<4;++i){ int tx=U.pos.first+dx[i],ty=U.pos.second+dy[i]; if(tx>=0 && tx<=5 && ty>=0 && ty<=tx){ ll nextst=U.st-pw[wei[tx][ty]]*(U.st/pw[wei[tx][ty]]%6ll); nextst+=pw[wei[U.pos.first][U.pos.second]]*(U.st/pw[wei[tx][ty]]%6ll); int tmp=calc(nextst); if(S.find(nextst)==S.end() && tmp<=(20-(U.d+1))*2){ if(nextst==goal){ ok=1; printf("%d\n",U.d+1); break; } S.insert(nextst); q.push(Node(nextst,Point(tx,ty),U.d+1)); } } } if(ok){ break; } } if(!ok){ puts("too difficult"); } } return 0; }
时间: 2024-12-24 18:18:14