• 分层图最短路 乱搞分享


    写在前面

      这篇写到的做法并不是真正的分层图,只是一个假的低配版算法。

      【我这么菜哪里会分层图呢?(╯▔皿▔)╯

      动态规划。

    问题

      【既然不是真的分层图,那么就不说什么是分层图了。

      该算法能解决的问题:

        在一张带权图上面,有k次机会修改边权【非同一条边,求从起点到终点的最短路。

      假如会分层图的话,就是一个板板。

    思考

      那么不会的话怎么办?

      总是会有一些巨巨给予菜鸡福音

      不知是哪位神犇想出来了简单的动态规划,解决了这个问题。

    解法

      首先确认,点数 * 修改次数 能够存成一个二维数组。

      然后,定义 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 电话线

    如果可以还是去学学分层图吧

  • 相关阅读:
    R语言介绍与安装
    待分析数据数值化
    网络环路与攻击和谷歌的四个8
    基于storm和hadoop的广告系统研究【5】
    Xpath语法
    Xcode编译工具
    关于Xcode的Other Linker Flags
    iOS项目的目录结构和开发流程
    Objective-C中关于NSArray, NSDictionary, NSNumber等写法的进化
    Windows 8 常见教程
  • 原文地址:https://www.cnblogs.com/qxyzili--24/p/11802537.html
Copyright © 2020-2023  润新知