题意大概就是八数码问题,只不过把空格的移动方式改变了:空格能够向前或向后移动一格或三格(循环的)。
分析:其实跟八数码问题差不多,用康托展开记录状态,bfs即可。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <cstdlib> #define Mod 1000000007 #define SMod 10007 #define INint 2147483647 #define LL (0x3f3f3f3f3f3f3f3f)*2 #define ll long long using namespace std; #define N 500007 struct node { ll cantor,cost; int pos; bool operator <(const node& a)const { return cost > a.cost; } }S,E; priority_queue<node> que; ll fact[11] = {1,1,2,6,24,120,720,5040,40320,362880,3628800}; int dx[4] = {1,-1,3,-3}; int a[11],b[11],Can[N][11],vis[N]; ll ans,ch,cv; ll Cantor(int *a) { int i,j; ll cnt; ll res = 0; for(i=0;i<9;i++) { cnt = 0; for(j=i+1;j<9;j++) if(a[i] > a[j]) cnt++; res += cnt*fact[8-i]; } return res; } void getcantor(ll cantor,int *a) { for(int i=0;i<9;i++) Can[cantor][i] = a[i]; } void geta(ll cantor) { for(int i=0;i<9;i++) a[i] = Can[cantor][i]; } void bfs() { while(!que.empty()) que.pop(); memset(vis,0,sizeof(vis)); int i,j; que.push(S); //vis[S.cantor] = 1; while(!que.empty()) { node tmp = que.top(); que.pop(); ll cantor = tmp.cantor; ll cost = tmp.cost; int pos = tmp.pos; if(vis[cantor]) continue; vis[cantor] = 1; if(cost >= ans) continue; if(cantor == E.cantor) { ans = min(ans,cost); break; } geta(cantor); for(int k=0;k<4;k++) { int v = (pos+dx[k]+9)%9; swap(a[v],a[pos]); ll newcantor = Cantor(a); if(vis[newcantor]) { swap(a[v],a[pos]); continue; } getcantor(newcantor,a); swap(a[v],a[pos]); node now; now.cantor = newcantor; now.pos = v; if(k < 2) now.cost = cost + ch; else now.cost = cost + cv; if(now.cost >= ans) continue; //vis[newcantor] = 1; que.push(now); } } } int main() { int i,j; while(scanf("%lld%lld",&ch,&cv) && (ch||cv)) { for(i=0;i<9;i++) { scanf("%d",&a[i]); if(a[i] == 0) S.pos = i; } S.cantor = Cantor(a); S.cost = 0; for(i=0;i<9;i++) scanf("%d",&b[i]); E.cantor = Cantor(b); getcantor(S.cantor,a); getcantor(E.cantor,b); ans = (1LL<<62); bfs(); printf("%lld\n",ans); } return 0; }