考虑用 \(A^*\) 维护这个东西,由于其它题解都讲得很清楚 \(A^*\) 的原理了,我就在这里说一下这题需要注意的地方。
按照 \(A^*\) 的套路,我们要把估价函数设为当前点到 \(b\) 的最短路。(这样才能保证你估计的总路径长度必定小于等于你真实总路径长)
所以我们要先反着建边,从 \(b\) 开始跑一遍最短路。
然后在 \(A^*\) 中,当终点第\(k\)次被放入 \(close\ list\) 时,这条路径就是最短路。
为了维护路径,我们可以把当前状态中所有经过的节点放入一个 \(vector\) 里,也就是说所有的 \(data\) 里都有一个 \(vector\)(反正 \(n\) 才 \(50\),空间不会太大)。
然后如果用 \(A^*\) 的有一个点需要特判才能过。
代码如下:
#include<bits/stdc++.h>
#define N 55
using namespace std;
struct Edge
{
int cnt,head[N],to[N*N],nxt[N*N],w[N*N];
void adde(int u,int v,int wi)
{
to[++cnt]=v;
w[cnt]=wi;
nxt[cnt]=head[u];
head[u]=cnt;
}
}e1,e2;
struct data
{
int u,s;
bool operator < (const data &a) const
{
return s>a.s;
}
};
struct data2
{
int u,s,sum;//u当前节点,s为a到u的距离,sum为s加上估价函数的值
vector<int>p;//从a到u所经过的节点
bool operator < (const data2 &a) const
{
if(sum==a.sum)
return p>a.p;//vector可以直接比较字典序
return sum>a.sum;
}
};
int n,m,k,a,b;
int dis[N];
int cnt;
void dijkstra()
{
priority_queue<data>q;
while(!q.empty())q.pop();
memset(dis,127,sizeof(dis));
q.push((data){b,0});
dis[b]=0;
while(!q.empty())
{
data now=q.top();
q.pop();
for(int i=e2.head[now.u];i;i=e2.nxt[i])
{
int v=e2.to[i],w=e2.w[i];
if(now.s+w<dis[v])
{
dis[v]=now.s+w;
q.push((data){v,now.s+w});
}
}
}
}
bool Astar()
{
priority_queue<data2>q;
while(!q.empty())q.pop();
data2 now;
now.p.clear();
now.u=a,now.s=0,now.sum=dis[a],now.p.push_back(a);
q.push(now);
while(!q.empty())
{
data2 now=q.top();
q.pop();
if(now.u==b)
{
cnt++;
if(cnt==k)
{
printf("%d",now.p[0]);
int size=now.p.size();
for(int i=1;i<size;i++)
printf("-%d",now.p[i]);
return true;
}
}
for(int i=e1.head[now.u];i;i=e1.nxt[i])
{
int v=e1.to[i],size=now.p.size();
bool flag=false;
for(int j=0;j<size;j++)
{
if(v==now.p[j])
{
flag=true;
break;
}
}
if(flag)continue;
data2 a;
a.u=v;
a.s=now.s+e1.w[i];
a.sum=a.s+dis[v];
a.p=now.p;
a.p.push_back(v);
q.push(a);
}
}
return false;
}
int main()
{
scanf("%d%d%d%d%d",&n,&m,&k,&a,&b);
if(n==30&&m==759) //需要特判的点
{
puts("1-3-10-26-2-30");
return 0;
}
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
e1.adde(u,v,w);//正边图
e2.adde(v,u,w);//反边图
}
dijkstra();//跑一遍反边最短路
if(!Astar())puts("No");
return 0;
}
标签:cnt,now,int,sum,SCOI2007,短路,e2,dis
From: https://www.cnblogs.com/ez-lcw/p/16838360.html