A算法基本模版:
特殊情况:当估计距离都为0时,则为dijkstra算法
A算法每个点可能会多次遍历到,所以不用st数组
A*算法必须有解时才能使用
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,string> PIS;
unordered_map<string,int> d;//到该点的真实距离
unordered_map<string,pair<string,char>> pre;//记录前驱状态和执行操作
priority_queue<PIS,vector<PIS>,greater<PIS>> heap;//状态和离终点的估计距离
//上下左右对应操作和坐标变换
int dx[]={-1,1,0,0},dy[]={0,0,-1,1};
char op[]={'u','d','l','r'};
//估计距离:记录状态中每个点到目标位置的曼哈顿距离之和
//每个点应该归位的距离之和
int f(string state)
{
int res=0;
for(int i=0;i<9;i++)
{
if(state[i]=='x')continue;
int t=state[i]-'1';
res+=abs(i/3-t/3)+abs(i%3-t%3);
}
return res;
}
string a_star(string start)
{
d[start]=0;
heap.push({f(start),start});
string end="12345678x";
while(heap.size())
{
auto t=heap.top();
heap.pop();
string state=t.second;
if(state==end)break;
//找出状态中x的位置,并进行操作
int x,y;
for(int i=0;i<9;i++)
{
if(state[i]=='x')
{
x=i/3;
y=i%3;
break;
}
}
//要记录下原本的状态,每次枚举变化后根据原本状态操作
string source=state;
for(int i=0;i<4;i++)
{
int vx=x+dx[i],vy=y+dy[i];
if(vx<0||vx>=3||vy<0||vy>=3)continue;
state=source;
swap(state[x*3+y],state[vx*3+vy]);
//遍历到一点的次数可能不止一次,所以要更新距离
if(d.count(state)==0||d[state]>d[source]+1)
{
d[state]=d[source]+1;
pre[state]={source,op[i]};
//将到state状态的距离和state到终点的预计距离加入heap中,从小依次枚举
heap.push({f(state)+d[state],state});
}
}
}
string res;
while(end!=start)
{
res+=pre[end].second;
end=pre[end].first;
}
reverse(res.begin(),res.end());
return res;
}
int main()
{
string start;
string check;//记录除了x的逆序对
for(int i=0;i<9;i++)
{
char c;
cin>>c;
start+=c;
if(c!='x')check+=c;
}
int res=0;
for(int i=0;i<8;i++)
{
for(int j=i;j<8;j++)
if(check[j]>check[i])res++;
}
if(res&1)puts("unsolvable");
else cout<<a_star(start);
return 0;
}
八数码问题,当x左右交换时不改变逆序对的数量,上下交换时逆序对的数量+2或者-2,最终状态逆序对数量为0,所以初始状态逆序对数量为偶数时才能有解。