poj 2449 Remmarguts' Date(第K短路问题 Dijkstra+A*)

时间:2021-11-11 13:40:20

http://poj.org/problem?id=2449

Remmarguts' Date
Time Limit: 4000MS   Memory Limit: 65536K
Total Submissions: 18168   Accepted: 4984

Description

"Good man never makes girls wait or breaks an appointment!" said the mandarin duck father. Softly touching his little ducks' head, he told them a story. 
"Prince Remmarguts lives in his kingdom UDF – United Delta of Freedom. One day their neighboring country sent them Princess Uyuw on a diplomatic mission." 
"Erenow, the princess sent Remmarguts a letter, informing him that she would come to the hall and hold commercial talks with UDF if and only if the prince go and meet her via the K-th shortest path. (in fact, Uyuw does not want to come at all)" 
Being interested in the trade development and such a lovely girl, Prince Remmarguts really became enamored. He needs you - the prime minister's help! 
DETAILS: UDF's capital consists of N stations. The hall is numbered S, while the station numbered T denotes prince' current place. M muddy directed sideways connect some of the stations. Remmarguts' path to welcome the princess might include the same station twice or more than twice, even it is the station with number S or T. Different paths with same length will be considered disparate. 

Input

The first line contains two integer numbers N and M (1 <= N <= 1000, 0 <= M <= 100000). Stations are numbered from 1 to N. Each of the following M lines contains three integer numbers A, B and T (1 <= A, B <= N, 1 <= T <= 100). It shows that there is a directed sideway from A-th station to B-th station with time T. 
The last line consists of three integer numbers S, T and K (1 <= S, T <= N, 1 <= K <= 1000).

Output

A single line consisting of a single integer number: the length (time required) to welcome Princess Uyuw using the K-th shortest path. If K-th shortest path does not exist, you should output "-1" (without quotes) instead.

Sample Input

2 2
1 2 5
2 1 4
1 2 2

Sample Output

14

Source

POJ Monthly,Zeyuan Zhu
 
【题解】:

给定一个图,求起点到终点的第k短路。

分析:先用dijkstra从t反向寻找最短路。然后使用A*算法,把f(i)=g(i) + h(i)。h(i)就是i点到t的最短距离。当某点出队次数达到k次的时候,结果为该点的当前路程+该点到t的最短距离。(我没有判断不连通的情况)

为什么这样做是对的呢?我们这样来思考,如果不实用最短路,而只使用A*那么t第x次出队的结果即为第x短路的距离。继而可以想到,从第一个出队次数达到x的点,沿着最短路走到t,一定是第x短路。

说实话我也没有完全理解。

另外注意s==t的情况,据说k要++,不明白为啥。

这个题用来测第k短路的模板真的再好不过了,累计我wa在这么几个地方:
1.起点和终点是同一点时一定要走,不能输出0;
2.用普通邻接矩阵的话要注意重边的问题(所以强烈推荐邻接表水所有题);

【code】:

 /**
Judge Status:Accepted Memory:9252K
Time:204MS Language:G++
Code Length:2590B Author:cj
*/ #include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<string.h> #define N 1005
#define M 200100
#define INF 1000000000
using namespace std; struct Edge
{
int v,next,c;
}edge[M]; struct Nod //A*中的优先队列数据类型
{
int v,d,h;
}; struct Dj //dijkstra中的优先队列数据类型
{
int u,dis;
}; bool operator < (Dj a,Dj b) //dijkstra中的优先对队重载<号
{
return b.dis<a.dis;
} bool operator < (Nod a,Nod b) //A*中的优先队列重载<号
{
return b.h+b.d<a.h+a.d;
} int head[N];
int tail[N];
int dis[N];
int visit[N];
int edge_cnt;
int cnt[N]; void init() //初始化
{
memset(head,-,sizeof(head));
memset(tail,-,sizeof(tail));
edge_cnt = ;
memset(visit,,sizeof(visit));
memset(cnt,,sizeof(cnt));
} void addEdge(int a,int b,int c)
{
edge[edge_cnt].v = b;
edge[edge_cnt].c = c;
edge[edge_cnt].next = head[a];
head[a] = edge_cnt++; //记录起始边 edge[edge_cnt].v = a;
edge[edge_cnt].c = c;
edge[edge_cnt].next = tail[b];
tail[b] = edge_cnt++; //记录结束边
}
void Dijkstra(int n,int t) //对于以各点为起点到t点的最短路径
{
priority_queue<Dj> p_q;
Dj now,temp;
int i;
for(i=;i<=n;i++) dis[i]=INF;
dis[t] = ;
temp.dis = ;
temp.u = t;
p_q.push(temp);
while(!p_q.empty())
{
temp = p_q.top();
p_q.pop();
if(visit[temp.u]) continue;
visit[temp.u] = ;
for(i=tail[temp.u];i!=-;i=edge[i].next)
{
int v = edge[i].v;
if(dis[v]>dis[temp.u]+edge[i].c)
{
dis[v]=dis[temp.u]+edge[i].c;
now.u = v;
now.dis = dis[v];
p_q.push(now);
}
}
}
} int Astar_Kth(int s,int t,int k)
{
Nod cur,nxt;
priority_queue<Nod> p_q;
cur.v = s;
cur.d = ;
cur.h = dis[s];
p_q.push(cur);
while(!p_q.empty())
{
cur = p_q.top();
p_q.pop();
cnt[cur.v]++;
if(cnt[cur.v]>k) continue;
if(cnt[t]==k) return cur.d;
int i;
for(i=head[cur.v];i!=-;i=edge[i].next)
{
int v = edge[i].v;
nxt.d = cur.d + edge[i].c;
nxt.v = v;
nxt.h = dis[v];
p_q.push(nxt);
}
}
return -;
} int main()
{
int n,m;
scanf("%d%d",&n,&m);
int i;
int a,b,c;
init();
for(i=;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
addEdge(a,b,c);
}
int s,t,k;
scanf("%d%d%d",&s,&t,&k);
if(s==t) k++;
Dijkstra(n,t);
printf("%d\n",Astar_Kth(s,t,k));
return ;
}