分层图最短路 乱搞分享

写在前面

  这篇写到的作法并非真正的分层图,只是一个假的低配版算法。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 电话线

若是能够仍是去学学分层图吧

相关文章
相关标签/搜索