題目鏈接:http://poj.org/problem?id=2449
題意
題目的意思很明確,就是讓你求s到t的第k短路。不過有一個trick點就是必須要經過路徑,也就是說如果s=t的話,在算第k短路時不能算s到t爲0這條路。
題解
基本就是裸的第k短路,而第k短路是單源最短路和A*算法的組合。對於A*算法,都知道f(n)=g(n)+h(n),這裏h(n)爲啓發式函數。我們令這裏的g(n)爲從源點s到n所經過的路徑,h(n)爲把所有邊反向後從終點t到n的最短路徑dist[n]。即估值=源點到當前點的距離+當前點到終點的最短距離。這時我們建一個優先隊列,每次彈出估值f()最小的點,如果彈出的點是t就計算t出隊的次數,如果次數等於k,那麼到當前點的距離g()即爲答案,否者就拓展與當前點相連的邊。
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <iostream>
#include <cstring>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;
const int maxn = 1e3+5;
const int maxm = 1e5+5;
int n,m,s,t,k,ans;
//前向星儲存邊
int head[maxn],A_head[maxn],cnt1,cnt2;
//dist[]儲存終點到其它點的最短路
int dist[maxn];
struct Edge{
int to,w,next;
}edge1[maxm],edge2[maxm];
struct A_Node{
int p,g,h;
bool operator < (A_Node tmp) const
{
return tmp.g+tmp.h < g+h;
}
};
typedef pair<int,int> P;
void init()
{
memset(head,-1,sizeof(head));
memset(A_head,-1,sizeof(A_head));
memset(dist,INF,sizeof(dist));
cnt1=cnt2=0;
}
void add_edge(int from,int to,int w,bool flag)
{
if(flag)
{
edge1[cnt1].to = to;
edge1[cnt1].w = w;
edge1[cnt1].next = head[from];
head[from] = cnt1++;
}
else
{
edge2[cnt2].to = to;
edge2[cnt2].w = w;
edge2[cnt2].next = A_head[from];
A_head[from] = cnt2++;
}
}
void Dijkstra() //優先隊列優化的Dijkstra求終點到其它點的最短路
{
priority_queue<P,vector<P>,greater<P> >pq;
P p;
dist[t] = 0;
pq.push(P(0,t));
while(!pq.empty())
{
p = pq.top(),pq.pop();
int u = p.second;
for(int i=head[u];i!=-1;i=edge1[i].next)
{
if(dist[edge1[i].to] > dist[u] + edge1[i].w)
{
dist[edge1[i].to] = dist[u]+edge1[i].w;
pq.push(P(dist[edge1[i].to],edge1[i].to));
}
}
}
}
void A_stra()
{
A_Node cur,next;
int num=0;
priority_queue<A_Node>pq;
//源點爲終點,不去掉爲0的路徑就相當於求第k+1短路
if(s==t) k++;
if(dist[s]==INF)
{
ans=-1;
return;
}
cur.p = s;
cur.g = 0;
cur.h = dist[s];
pq.push(cur);
while(!pq.empty())
{
cur = pq.top(),pq.pop();
if(cur.p==t) num++;
if(num==k)
{
ans = cur.g;
return;
}
for(int i=A_head[cur.p];i!=-1;i=edge2[i].next)
{
next.p = edge2[i].to;
next.g = cur.g+edge2[i].w;
next.h = dist[next.p];
pq.push(next);
}
}
ans = -1;
return;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
init();
int u,v,w;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add_edge(v,u,w,true);
add_edge(u,v,w,false);
}
scanf("%d%d%d",&s,&t,&k);
Dijkstra();
A_stra();
printf("%d\n",ans);
}
return 0;
}