A*算法的作用也是压缩搜索空间
①将BFS的队列换成优先队列
②按 估价函数 = 起点到当前点的真实距离+当前点到终点的估计距离 排序
③ 估价函数必须 真实值
第K短路
题意:从起点 S 到终点 T 的第 K 短路的长度
思路:首先考虑估价函数,每个点的估价函数设置为已经从起点出发的实际距离+到终点的最短距离,后者反向建图跑dijkstra计算得到,然后使用以估价函数从小到大排序的优先队列进行BFS,当第K次遇到终点时,此时已经从起点出发的实际距离即为第K短路的长度
注意: ①如果起点和终点重合,则求的是第K+1短路,此时最短路为0
②如果起点和终点不连通,在Astar中特判,否则会一直搜索所有情况导致超时
//从终点开始反向dijkstra,计算每个点到终点的距离
void dijkstra(){
memset(disr,0x3f,sizeof disr);
disr[T]=0;
priority_queue<PII,vector<PII>,greater<PII> > heap;
heap.push({disr[T],T});
while(heap.size()){
PII t=heap.top();heap.pop();
int distance=t.first,ver=t.second;
vis[ver]=true;
for(int i=hr[ver];~i;i=ner[i]){
int j=er[i];
if(vis[j]) continue;
if(disr[j]>distance+wr[i]){
disr[j]=distance+wr[i];
heap.push({disr[j],j});
}
}
}
}
//BFS
int Astar(){
if(disr[S]==0x3f3f3f3f) return -1;
priority_queue<PIII,vector<PIII>,greater<PIII> > q;
int cnt=0;
q.push({disr[S],{0,S}});
while(q.size()){
PIII t=q.top();q.pop();
int distance=t.second.first,ver=t.second.second;
if(ver==T){
cnt++;
if(cnt==K) return distance;
}
for(int i=h[ver];~i;i=ne[i]){
int j=e[i];
//估价函数为 到起点的实际距离+到终点的最短距离
q.push({distance+w[i]+disr[j],{distance+w[i],j}});
}
}
return -1;
}
八数码
题意:
形如转换成 ,其中X可以和上下左右交换,求所需要的最短交换路径
思路:估价函数为 当前状态离初始状态走过的距离 加上 当前每个位置离正确位置的曼哈顿距离之和
注意:如果初始状态中逆序对为奇数,则不可能转换到最终状态
typedef pair<int,pair<string,string> >PISS;
string w=" ";
string ed=" 12345678x";
map<string,bool> vis;
bool check(string str)//偶数逆序对可解
{
int cnt=0;
for(int i=1;i<=9;i++)
for(int j=i+1;j<=9;j++){
if(str[i]=='x'||str[j]=='x') continue;
if(str[i]>str[j]) cnt++;
}
if(cnt&1) return false;
return true;
}
int h(string s){
int d=0;
for(int i=1;i<=9;i++){
int x=(i-1)/3+1,y=(i-1)%3+1;
int c;
if(isdigit(s[i])) c=s[i]-'0';
else c=9;
int xx=(c-1)/3+1,yy=(c-1)%3+1;
d+=abs(x-xx)+abs(y-yy);
}
return d;
}
string Astar(){
priority_queue<PISS,vector<PISS>,greater<PISS> > q;
q.push({h(w),{"",w}});
vis[w]=true;
while(!q.empty()){
PISS t=q.top();q.pop();
string path=t.second.first;
string ver=t.second.second;
if(ver==ed){
return path;
}
int pos;
for(int i=1;i<=9;i++){
if(ver[i]=='x'){
pos=i;
break;
}
}
int x=(pos-1)/3+1,y=(pos-1)%3+1;
if(x>=2){
string tmp=ver;
swap(tmp[pos],tmp[pos-3]);
if(!vis[tmp]){
vis[tmp]=true;
q.push({path.length()+h(tmp),{path+"u",tmp}});
}
}
if(x<=2){
string tmp=ver;
swap(tmp[pos],tmp[pos+3]);
if(!vis[tmp]){
vis[tmp]=true;
q.push({path.length()+h(tmp),{path+"d",tmp}});
}
}
if(y>=2){
string tmp=ver;
swap(tmp[pos],tmp[pos-1]);
if(!vis[tmp]){
vis[tmp]=true;
q.push({path.length()+h(tmp),{path+"l",tmp}});
}
}
if(y<=2){
string tmp=ver;
swap(tmp[pos],tmp[pos+1]);
if(!vis[tmp]){
vis[tmp]=true;
q.push({path.length()+h(tmp),{path+"r",tmp}});
}
}
}
}
int main(){
for(int i=1;i<=9;i++){
char c;cin>>c;
w+=c;
}
if(!check(w)){
cout<<"unsolvable";
return 0;
}
cout<<Astar();
}