這篇寫到的作法並非真正的分層圖,只是一個假的低配版算法。node
【我這麼菜哪裏會分層圖呢?(╯▔皿▔)╯ios
動態規劃。算法
【既然不是真的分層圖,那麼就不說什麼是分層圖了。數組
該算法能解決的問題:ide
在一張帶權圖上面,有k次機會修改邊權【非同一條邊,求從起點到終點的最短路。spa
假如會分層圖的話,就是一個闆闆。code
那麼不會的話怎麼辦?blog
老是會有一些巨巨給予菜雞福音。get
不知是哪位神犇想出來了簡單的動態規劃,解決了這個問題。string
首先確認,點數 * 修改次數 可以存成一個二維數組。
而後,定義 dp[ i ][ j ]表示從起點到 j 的最短路【修改 i 次
觀察定義咱們能夠發現:
對於每一種狀況,咱們只須要跟普通的dp同樣,分紅選與不選兩種狀況討論。
惟一的不一樣就是,通常的dp是在求 i 的時候,使用 i-1 轉移,可是如今是從 i 直接向 i+1 進行轉移。
關於計算咱們能夠把最短路修改一部分,獲得下面的式子
if(nw.x+tr[i].val<dis[num][y]) { dis[num][y]=nw.x+tr[i].val; q[num].push((node){dis[num][y],y}); } if(num!=k&&nw.x<dis[num+1][y]) { dis[num+1][y]=nw.x; q[num+1].push((node){dis[num+1][y],y}); }
這樣的話,咱們經過k次最短路的計算最後輸出dp[ k ][ n ]就ok。
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int maxn=50009; int n,m,k; int head[maxn],ecnt; struct ss{ int to,nxt,val; }tr[maxn<<1]; inline void add(int a,int b,int c) { tr[++ecnt].nxt=head[a]; tr[ecnt].to=b; tr[ecnt].val=c; head[a]=ecnt; return; } int dis[25][maxn];//通過k次改造以後到i的最短路 struct node{ int x,id; bool operator < (const node &a) const{ return x>a.x; } }; priority_queue<node> q[25]; bool vis[25][maxn]; void dij(int num) { while(!q[num].empty()) { node nw=q[num].top(); q[num].pop(); int x=nw.id; if(vis[num][x]) continue; vis[num][x]=1; for(int i=head[x];i;i=tr[i].nxt) { int y=tr[i].to; if(vis[num][y]) continue; if(nw.x+tr[i].val<dis[num][y]) { dis[num][y]=nw.x+tr[i].val; q[num].push((node){dis[num][y],y}); } if(num!=k&&nw.x<dis[num+1][y]) { dis[num+1][y]=nw.x; q[num+1].push((node){dis[num+1][y],y}); } } } return; } int main() { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } for(int i=0;i<=k;i++) for(int j=1;j<=n;j++) dis[i][j]=1e9; dis[0][1]=0; q[0].push((node){0,1}); for(int i=0;i<=k;i++) dij(i); cout<<dis[min(m,k)][n]<<endl; return 0; }