题解 P2901 【[USACO08MAR]Cow Jogging G】
\color{green}{\text{Front Knowledge - A}^{*} \text{ algorithm}}
A* 算法,就是启发式的 BFS 算法。它依赖于以下几个函数:
我们的 A*算法 就是根据
为了保证正确性,我们要求 A*算法 速度越快,所以
\color{green}{\text{K}^{\text{th}} \text{ Shortest Path}}
顾名思义,就是求一张图的第
考虑暴力,我们可以求出所有的可能路径,然后排序,取第 TLE。
考虑如何用 A* 算法。
我们发现这个
这么做还有一个好处,就是第
1.求出所有的 dis (一遍SPFA/dijkstra) 搞定
2.把起点入队列
3.扩展 dis + t 最小的点
4.然后它是终点,则记录,如果求出 K 短路,再见
5.不断进行 3 直至出解
\color{green}{\text{P2901\ \ \ \ \ [USACO08MAR]Cow Jogging G}}
typedef long long ll;int n,m,k;
const int N=1e3+100,M=1e6+100;
struct edge{int next,to;ll len;};
edge e[M],E[M];int h[N],H[N],tot,Tot;
inline void add(int a,int b,int c){
e[++tot]=(edge){h[a],b,c};h[a]=tot;
}//链式前向星——正向图
inline void Add(int a,int b,int c){
E[++Tot]=(edge){H[a],b,c};H[a]=Tot;
}//链式前向星——反向图
int dis[N];//点到终点的长度
bool vis[N];//SPFA判重用数组
inline void spfa_algorithm(){
queue<int> q;q.push(1);
memset(dis,127,sizeof(dis));
memset(vis,true,sizeof(vis));
vis[1]=false;dis[1]=0;
while (q.size()){
int u=q.front();q.pop();vis[u]=1;
for(int i=H[u];i;i=E[i].next){
register int to=E[i].to;
if (dis[to]>dis[u]+E[i].len){
dis[to]=dis[u]+E[i].len;//updata
if (vis[to]){vis[to]=0;q.push(to);}
}//单源最短路的松弛操作
}//特别注意,我们跑的是反向图
}
}
struct node{int pos;ll len;};
bool operator < (node a,node b){
return a.len+dis[a.pos]>b.len+dis[b.pos];
}//特别注意,因为使用了STL的优先队列
//所以这里的“小于”必须定义为“大于”
int A_star_algorithm(int &ret){
priority_queue<node> q;
q.push((node){n,0});
while (q.size()){
node z=q.top();q.pop();
if (z.pos==1){//又到终点了
printf("%lld\n",z.len);
if ((--ret)==0) return 0;
}
register int u=z.pos,i;
for(i=h[u];i;i=e[i].next){
register int to=e[i].to;
q.push((node){to,z.len+e[i].len});
}
}
return ret;
}
int main(){
n=read();m=read();k=read();
for(int i=1,u,v,w;i<=m;i++){
u=read();v=read();w=read();
add(u,v,w);Add(v,u,w);
}
spfa_algorithm();
A_star_algorithm(k);
while (k--) printf("-1\n");
return 0;
}
read() 函数就是快读函数(我写得丑,就不给大家了)
大家有空可以做做这题:模板】k短路 / [SDOI2010]魔法猪学院。它卡 STL 哦·!!!