这题要用到A*。每个状态N记录个f(N)值,等于从初始状态走到该状态的实际花费g(N)+从该状态到目标状态花费的估计值h(N)。h(N)要小于等于从该状态到目标状态的实际花费。h(N):棋盘上剩余点到出口的曼哈顿距离之和。
在BFS时,优先考虑f(N)值小的,在f(N)相同时,考虑当前花费g(N)小的。为了每次找到f(N)最小的点,可以用堆(STL中的优先队列)来保存状态。
状态表示:最多四个棋子,坐标最大是n(n<=6),所以可以用一个整数来表示,相当于n进制数。
BFS时的状态扩展就很简单了,每个棋子都可向四个方向走一步,判断走的位子是否在棋盘内,是否是空的,是否和其他棋子相邻。每次走后最小的棋后判断是否在出口,是的话就拿掉了。
#include<cstdio> #include<cstring> #include<cstdlib> #include<string> #include<cmath> #include<iostream> #include<algorithm> #include<deque> #include<queue> #include<vector> using namespace std; typedef struct{ int f,num,t; int loc[4]; }node; int check[2000000],n,m,a[8][8],exitloc,mod; struct cmp{ bool operator()(const node& a,const node& b){ if(a.f>b.f) return true; if(a.f==b.f && check[a.num]>check[b.num]) return true; return false; } }; priority_queue<node,vector<node>,cmp> Q; int trans(node nd,int m){ int num=0,i; for(i=0; i<m; i++){ num*=mod; num+=nd.loc[i]; } return num; } void ini(int n,int m){ int k=1,i,j; for(i=0; i<m; i++) k*=mod; for(i=0; i<=k; i++) check[i]=0; for(i=0; i<n; i++) for(j=0; j<n; j++) a[i][j]=0; } int H(node nd){ int i,num=0,k; for(i=0; i<m; i++) { k=nd.loc[i]; if(k!=0) num+=abs((k-1)/n - (exitloc-1)/n) + abs((k-1)%n - (exitloc-1)%n); } return num; } void BFS(){ int k,i,j,xx,yy,x,y,min,num2,t; node nd,nd2; while(!Q.empty()){ nd=Q.top(); Q.pop(); if(check[0]>0)return; min=m; for(i=0; i<m; i++){ k=nd.loc[i]; if(k==0) continue; a[(k-1)/n][((k-1)%n)]=i+1; if(i+1<min) min=i+1; } for(i=min-1; i<m; i++){ k=nd.loc[i]; xx=(k-1)/n; yy=(k-1)%n; a[xx][yy]=0; for(j=0; j<4; j++){ x=xx; y=yy; if(j==0) x--; else if(j==1) x++; else if(j==2) y--; else if(j==3) y++; if(x>=0 && x<n && y>=0 && y<n && a[x][y]==0) if((x==0 || a[x-1][y]==0) && (y==0 || a[x][y-1]==0) && (x==n-1 || a[x+1][y]==0) && (y==n-1 || a[x][y+1]==0)){ nd2=nd; nd2.loc[i]=x*n+y+1; t=0; if(i==min-1 && x*n+y+1==exitloc) {nd2.loc[i]=0; t=1;} num2=trans(nd2,m); if(check[num2]>0) continue; check[num2]=check[nd.num]+1; nd2.num=num2; nd2.t=nd.t-t; nd2.f=H(nd2)+check[nd2.num]; Q.push(nd2); } } a[xx][yy]=i+1; } for(i=0; i<m; i++){ k=nd.loc[i]; if(k==0) continue; a[(k-1)/n][((k-1)%n)]=0; } } } int main() { int T,i,j,k; char s[10],ch; node nd; cin>>T; while(T--) { scanf("%d %d",&n,&m); while(!Q.empty())Q.pop(); mod=n*n+1; gets(s); for(i=0; i<n; i++) { gets(s); for(j=0; j<n; j++) if(s[j]=='x') exitloc = i*n + j + 1; else if(s[j]>='1' && s[j]<='0'+m) nd.loc[s[j]-'1'] = i*n + j + 1; } ini(n,m); k=trans(nd,m); check[k]=1; nd.num=k; nd.f=H(nd)+check[nd.num]; nd.t=m; Q.push(nd); BFS(); printf("%d\n",check[0]-1); } return 0; }