POJ 2449 Remmarguts` Date
K短路,A*算法+dijkstra
传送门:POJ
题意
给你个图,给起点终点,k。求第k短路。注意必须走路,不能不走。
思路
初学A*算法。膜大佬
说说自己的理解吧。概念什么的就不说了。对比着dijkstra算法说:
建图的时候建两个,一个正向建,一个反向建,反向就是一条路起点终点反过来,距离不变。
先用dijkstra跑一遍反向的图,求出估值函数hx——终点到各点距离,A*算法更新需要用。
dij里面有个d数组,记录距离的,而A*算法没有,因为求得不是最短路,没法更新d数组,所以距离保存在优先队列里面。
需要一个数组,记录A*中某点的出队次数,出队一次代表以它为更新点更新了别人一次,终点t更新了k次后就是k短路。可以终止更新。
A*队列里这样封装数据:
int point;//当前点 int g;//fx,表示当前点到终点的距离 int dis;//表示起点到当前点的距离 bool operator <(const Queue &a) const { return g+dis>a.g+a.dis; }
每次取队首元素,就是总距离最小的元素,对所连边更新。
如果不算反向图的距离,感觉就是dijkstra。。。每次选最短的路更新周围的点。。
代码
注意一下,如果起点s==终点t,那么k需要+1,因为这种情况有一条路是什么都不走,这是“第一短路”,而题目要求必须走路
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
const int MAXN=200007;
const int oo=1000000007;
typedef long long LL;
struct Graph{
int next;
int to;
int cost;
}G_inv[MAXN],G[MAXN];
int head[MAXN],head_inv[MAXN];
struct Queue{
int point;//当前点
int g;//fx,表示当前点到终点的距离
int dis;//表示起点到当前点的距离
Queue(){}
Queue(int _point,int _dis,int _g){ point=_point;dis=_dis;g=_g; }
bool operator <(const Queue &a) const
{
return g+dis>a.g+a.dis;
}
};
int d_inv[MAXN];
int dijkstra(int n,int m,int s,int t)//点数,边数,起点,终点
{
memset(d_inv,0x3f,sizeof(d_inv));
priority_queue<Queue> que;
d_inv[s]=0;
while(!que.empty()) que.pop();
que.push(Queue(s,0,0));
while(!que.empty())
{
Queue temp=que.top();
que.pop();
if(temp.dis>d_inv[temp.point]) continue;
int pn=temp.point;
if(d_inv[pn]<temp.dis) continue;
for(int i=head_inv[pn];i!=-1;i=G_inv[i].next)
{
int dis1,to1;
dis1=temp.dis+G_inv[i].cost;
to1=G_inv[i].to;
if(dis1<d_inv[to1])
{
d_inv[to1]=dis1;
que.push(Queue(to1,dis1,0));
}
}
}
return d_inv[t];
}
int refresh[MAXN];
int astar(int s,int t,int k)
{
priority_queue<Queue> que;
memset(refresh,0,sizeof(refresh));
while(!que.empty()) que.pop();
que.push(Queue(s,0,d_inv[s]));
while(!que.empty())
{
Queue temp=que.top();
que.pop();
int po=temp.point;
refresh[po]++;
if(refresh[po]>k) continue;
if(refresh[t]==k) return temp.dis;
for(int i=head[po];~i;i=G[i].next)
{
int v=G[i].to;
int disn=G[i].cost+temp.dis;
que.push(Queue(v,disn,d_inv[v]));
}
}
return -1;//没有k短路,输出-1
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2)
{
memset(head,-1,sizeof(head));
memset(G,0,sizeof(G));
memset(head_inv,-1,sizeof(head_inv));
memset(G_inv,0,sizeof(G_inv));
for(int i=0;i<m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
G[i].to=b;G[i].cost=c;G[i].next=head[a];head[a]=i;
swap(a,b);
G_inv[i].to=b;G_inv[i].cost=c;G_inv[i].next=head_inv[a];head_inv[a]=i;
}
int s,t,k;
scanf("%d%d%d",&s,&t,&k);
dijkstra(n,m,t,s);
if(s==t) k++;
printf("%d\n",astar(s,t,k));
}
return 0;
}