分層圖最短路 亂搞分享

寫在前面

  這篇寫到的作法並非真正的分層圖,只是一個假的低配版算法。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。

菜題練手

  P2939 改造路

#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;
}
附送 P2939 代碼一份

  P2296 尋找道路

  P4822 凍結

  P4568 飛行路線

  P1948 電話線

若是能夠仍是去學學分層圖吧

相關文章
相關標籤/搜索