poj2449 Remmarguts' Date(第k短路問題)(A*+spfa/dijkstra)
思路來源
https://blog.csdn.net/berrykanry/article/details/78345894(通俗易懂解釋好評)
https://www.cnblogs.com/yyf0309/p/8438849.html(可惜看不懂可持久化可並堆)
題意
給定一個圖,求第k短路,
相同長度不同路徑的路被認為是不同的路,
若不存在輸出-1。
題解
我才不會說我八數碼題tleMLE了兩天後補了一下A*演算法又被安利來看這個破題
以終點為S進行dijkstra/spfa,
(具體實現可以建反向圖)
然後得到了真實的評估函式h(n)的表,
這樣我到了一個點,就知道已走路g(n)+前方最短路h(n)這條路的cost,
把它記為截止到該點的理想最短路。
顯然,我們從起點dis[n]即最短路開始延展,
相當於bfs,由起點轉向其一步可達點,
即由最短路,轉向了後續狀態可能換了一條邊的最短路。
後者是實際意義上的次短,第三短等等等…
而沒換邊的路,被加進優先佇列裡之後,
由於其距離小,還應處在隊頂的位置,只是其截止點往後推了一個,
若不存在環,最終所有點的截止點都會被推到終點,
而我們只需要這其中的前k個。
而由於優先佇列按距離排序,
當其到達終點的時候,對終點計貢獻,
說明這些路是截止到終點的,長度嚴格遞增的路。
當計到第k時,即為起點可達終點的k短路。
這個題,引發了我深深的感慨。
在人生之路上,當你還在為自己的前途備一個list,
記錄第一志願,第二志願,……,第k志願並在線為其比較的時候,
早就有人已經洞若觀火,知道自己第一志願應該報哪,
並且,為了選擇第k志願,明明知道最短路在哪,
不惜比照著自己已經打好的dijkstra表,
開始往那些非最短路的地方瞎走???
瞎走一步,啊,這次走到了次短路,加到佇列裡,
瞎走兩步…瞎走k步,啊終於找到了我要的k短路
高考空了50分 終於考上了理想第k大學 既視感
程式碼
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <cmath> #include <set> #include <map> #include <vector> #include <stack> #include <queue> #include <functional> const int INF=0x3f3f3f3f; const int maxn=1e5+10; const int mod=1e9+7; const int MOD=998244353; const double eps=1e-7; typedef long long ll; #define vi vector<int> #define si set<int> #define pii pair<int,int> #define pi acos(-1.0) #define pb push_back #define mp make_pair #define lowbit(x) (x&(-x)) #define sci(x) scanf("%d",&(x)) #define scll(x) scanf("%lld",&(x)) #define sclf(x) scanf("%lf",&(x)) #define pri(x) printf("%d",(x)) #define rep(i,j,k) for(int i=j;i<=k;++i) #define per(i,j,k) for(int i=j;i>=k;--i) #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; int n,m,s,t,k; int head[1005],cnt,rehead[1005],qq[5005]; bool vis[1005]; int dis[1005]; struct edge{int to,nex,w;}e[100005],re[100005]; struct node { int g;//當前已走 int f;//總 int id;//節點號 node(int a,int b,int c):g(a),f(b),id(c){ } }; bool operator>(node a,node b) { if(a.f!=b.f)return a.f>b.f; return a.g>b.g; } priority_queue<pii,vector<pii>,greater<pii> >q; priority_queue<node,vector<node>,greater<node> >p; void init() { mem(head,-1); cnt=0; mem(rehead,-1); mem(vis,0); } void add(int u,int v,int w) { e[cnt].to=v;//u->v e[cnt].w=w; e[cnt].nex=head[u]; head[u]=cnt; re[cnt].to=u;//v->u re[cnt].w=w; re[cnt].nex=rehead[v]; rehead[v]=cnt++; } void spfa(int src) { for(int i = 1; i <= n; i++) dis[i] = INF; mem(vis,0); int h = 0, t = 1; qq[0] = src; dis[src] = 0; while(h < t) { int u = qq[h++]; vis[u] = 0; for(int i = rehead[u] ; i != -1; i = re[i].nex) { int v = re[i].to; int w = re[i].w; if(dis[v] > dis[u] + w) { dis[v] = dis[u] + w; if(!vis[v]) { qq[t++] = v; vis[v] = 1; } } } } } int astar(int s,int t) { int num=0; if(s==t)k++;//注意這裡,我們把s->s視作為0的最短路 if(dis[s]==INF)return -1; while(!p.empty())p.pop(); p.push(node(0,dis[s],s));//以t為視角的距離 while(!p.empty()) { node tmp=p.top(); p.pop(); int g=tmp.g,f=tmp.f,u=tmp.id; if(u==t) { num++; if(num==k)return g; } for(int j=head[u];~j;j=e[j].nex) { int v=e[j].to,w=e[j].w; p.push(node(g+w,g+w+dis[v],v)); } } return -1; } int main() { while(~scanf("%d%d",&n,&m)) { init(); rep(i,0,m-1) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); } scanf("%d%d%d",&s,&t,&k); spfa(t);//對終點dijkstra printf("%d\n",astar(s,t)); } return 0; }