my
八数码问题
\(A*\) 算法例题。
首先判断是否有解。这里有一个条件:将八数码转化为序列后如果逆序对数为偶数,一定有解,否则一定无解。
充分性难证明,只证明必要性:只要是有解必定是偶数。
行内移动序列没有变,数量不变。
如果上下移动发现逆序对变化是 \([0,±2]\)。
而答案序列逆序对为 \(0\),为偶数。先证明到这里。。。
显然估价函数应该设置为所有数与它目标位置之间的曼哈顿距离之和,因为每次最多只能将一个数向目标位置靠近,而且一般不能达到最好的情况。
#include<bits/stdc++.h>
using namespace std;
#define f first
#define s second
typedef pair<int,string> PIS;
int f(string state){
int res=0;
for(int i=0;i<state.size();++i){
int t=state[i]-49;
res+=abs(i/3-t/3)+abs(i%3-t%3);
}
return res;
}
string bfs(string start){
const int dx[]={-1,1,0,0},dy[]={0,0,-1,1};
string op="udlr";
string end="12345678x";
unordered_map<string,int>dist;
unordered_map<string,pair<string,char>>prev;
priority_queue<PIS,vector<PIS>,greater<PIS>>heap;
heap.push({f(start),start});
dist[start]=0;
while(!heap.empty()){
auto t=heap.top();
heap.pop();
string state=t.s;
if(state==end)break;
int step=dist[state];
int x,y;
for(int i=0;i<state.size();++i)
if(state[i]=='x'){
x=i/3,y=i%3;
break;
}
string source=state;
for(int i=0;i<4;++i){
state=source;
int a=x+dx[i],b=y+dy[i];
if(a>=0&&a<3&&b>=0&&b<3){
swap(state[x*3+y],state[a*3+b]);
if(!dist.count(state)||dist[state]>step+1){
dist[state]=step+1;
prev[state]={source,op[i]};
heap.push({dist[state]+f(state),state});
}
}
}
}
string res;
while(end!=start){
res+=prev[end].s;
end=prev[end].f;
}
reverse(res.begin(),res.end());
return res;
}
int main(){
string g,seq;
char c;
while(cin>>c){
g+=c;
if(c!='x')seq+=c;
}
int t=0;
for(int i=0;i<8;++i)
for(int j=i+1;j<8;++j)
if(seq[i]>seq[j])++t;
if(t&1)puts("unsolvable");
else puts(bfs(g).c_str());
return 0;
}