题目链接:传送门
题意:
一个九宫格,给定你初始状态和结束状态,每次横向移动和纵向移动都有一定的花费,
问从初始状态到结束状态的最小花费。
分析:
BFS,用优先队列维护到达当前状态的最优值,用hash判断当前的状态是否达到过。
代码如下:
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <queue> using namespace std; const int INF = 1e9+7777; int fac[9]= {1,1,2,6,24,120,720,5040,40320}; //康托展开,用来hash struct nod { int mp[9],pos,cost; bool operator <(const struct nod &tmp)const { return this->cost > tmp.cost; } } P; int dx[4]= {1,-1,0,0}; int dy[4]= {0,0,-1,1}; int s[9],e[9]; int cv,ch; int vis[40320*9+100]; int getHashVal(int *a) { //hash得到hash值。 int val = 0; for(int i=0; i<9; i++) { int cnt=0; for(int j=0; j<i; j++) cnt+=(a[j]>a[i]); val+=cnt*fac[i]; } return val; } bool check(nod tmp) { int cnt = 0; for(int i=0; i<9; i++) cnt+=(tmp.mp[i]==e[i]); return cnt==9; } int BFS(nod st) { priority_queue<nod> Q; Q.push(st); vis[getHashVal(st.mp)]=0; while(!Q.empty()) { nod top = Q.top(); Q.pop(); if(check(top)) { return top.cost; } for(int i=0; i<4; i++) { int tmppos = top.pos; int nowx = (top.pos/3+dx[i]+3)%3;//转换 int nowy = top.pos%3+dy[i]; if(nowy==3){ nowy=0; nowx=(nowx+1)%3; } if(nowy==-1){ nowy=2; nowx=(nowx-1+3)%3; } swap(top.mp[nowx*3+nowy],top.mp[tmppos]); if(i<2) top.cost+=cv; else top.cost+=ch; top.pos=nowx*3+nowy; int val = getHashVal(top.mp); if(top.cost<vis[val]) { Q.push(top); vis[val]=top.cost; } swap(top.mp[nowx*3+nowy],top.mp[tmppos]); if(i<2) top.cost-=cv; else top.cost-=ch; top.pos=tmppos; } } } nod init() { nod st; for(int i=0; i<40320*9+100; i++) vis[i]=INF; for(int i=0; i<9; i++) { st.mp[i]=s[i]; if(s[i]==0) st.pos=i; } st.cost=0; return st; } int main() { while(~scanf("%d%d",&ch,&cv)) { if(cv==0&&ch==0) break; for(int i=0; i<9; i++) scanf("%d",s+i); for(int i=0; i<9; i++) scanf("%d",e+i); printf("%d\n",BFS(init())); } return 0; } /* 4 9 6 3 0 8 1 2 4 5 7 6 3 0 8 1 2 4 5 7 31 31 4 3 6 0 1 5 8 2 7 0 3 6 4 1 5 8 2 7 92 4 1 5 3 4 0 7 8 2 6 1 5 0 4 7 3 8 2 6 12 28 3 4 5 0 2 6 7 1 8 5 7 1 8 6 2 0 3 4 0 31 96 312 */