1. 程式人生 > >【模板】POJ 2449 K短路(A*+dijkstra)

【模板】POJ 2449 K短路(A*+dijkstra)

Remmarguts’ Date
Time Limit: 4000MS Memory Limit: 65536K
Total Submissions: 28521 Accepted: 7746
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貪心+終點的出堆次數就為次數短路 我們可以記一個cnt記錄出堆次數 判斷一下得到答案
但是 這樣會TLE 因為我們這一演算法的複雜度與k和n相關
我們用A*優化,A*演算法可以改變搜尋範圍讓我們更快得到想要的答案
A*:公式表示為: f(n)=g(n)+h(n)
其中 f(n) 是從初始點經由節點 n 到目標點的估價函式,
g(n) 是在狀態空間中從初始節點到 n 節點的實際代價,
h(n) 是從 n 到目標節點最佳路徑的估計代價。
即估價函式 = 當前值 + 當前位置到終點的距離
保證找到最短路徑(最優解的)條件,關鍵在於估價函式 f(n)的選取:
一、估價值 h(n)<= n 到目標節點的距離實際值,這種情況下,搜尋的點數多,搜尋範圍大,效率低。但能得到最優解。
二、 如果 h(n)=d(n),即距離估計 h(n)等於最短距離,那麼搜尋將嚴格沿著最短路徑進行, 此時的搜尋效率是最高的。
三、如果 h(n) > d(n),搜尋的點數少,搜尋範圍小,效率高,但不能保證得到最優解。
f*(n)=g*(n) +h*(n)
f*(n) :從初始節點 S0 出發,經過節點 n 到達目標節點的最小步數 (真實值)。
g*(n): 從 S0 出發,到達 n 的最少步數(真實值)
h*(n): 從 n 出發,到達目標節點的最少步數(真實值)
估價函式 f(n)則是 f*(n)的估計值。
我們怎麼來確定真正的最短的長度呢?
SPFA!
因為題目是一個有向圖,那麼我們可以建一個反向圖,來記錄一下終點到起點的最短路, 這樣我們的估價就有一個準確的參考了,最起碼用SPFA估價會我們的答案會更接近正解而不是遠離它。

程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 233333;
int h[maxn],n,m,ss,tt,k;
bool vis[maxn],flag;
int tot1,fst1[maxn],nxt1[maxn];
int tot,fst[maxn],nxt[maxn];
struct heap
{
    int
id; int g; bool operator < (const heap &hah)const { return g + h[id] > hah.g + h[hah.id]; } }; struct Edge{ int from,to,cost; }es[maxn],es1[maxn]; void build(int f,int t,int d) { es[++tot] = (Edge){f,t,d}; nxt[tot] = fst[f]; fst[f] = tot; } void build1(int f,int t,int d) { es1[++tot1] = (Edge){f,t,d}; nxt1[tot1] = fst1[f]; fst1[f] = tot1; } queue<int>q1; void spfa() { memset(h,0x3f,sizeof(h)); q1.push(tt); h[tt] = 0; while(!q1.empty()) { int u = q1.front(); vis[u] = 0; q1.pop(); for(int i = fst1[u];i;i = nxt1[i]) { int v = es1[i].to; if(h[v] > h[u] + es1[i].cost) { h[v] = h[u] + es1[i].cost; if(!vis[v]) { vis[v]=1; q1.push(v); } } } } } priority_queue<heap>q; void Astar() { q.push((heap){ss,0}); int cnt = 0; while(!q.empty()) { heap u = q.top(); q.pop(); if(u.id == tt) { cnt ++; if(cnt == k) { flag = 1; printf("%d",u.g); return; } } for(int i = fst[u.id];i;i = nxt[i]) { int v = es[i].to; q.push((heap){v,u.g + es[i].cost}); } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { int a,b; int c; scanf("%d%d%d",&a,&b,&c); build(a,b,c); build1(b,a,c); } scanf("%d%d%d",&ss,&tt,&k); if(ss == tt) k++; spfa(); Astar(); if(!flag) puts("-1"); return 0; }