• 路【邻接矩阵存图找最短路】


    问题 F: 路

    传送门  来源: upc12787

    题目描述

    Farmer John 热衷于散步,每天早上他都要从 1 号仓库走到 n 号仓库。 Farmer John 家的 n 个仓库被 m 条双向道路连通起来,每条道路有一个长度 w。而Farmer John 又不喜欢走路,所以他走的是从 1 号仓库到 n 号仓库的最短路。
    但是 Farmer 的奶牛们总想搞点事情,他们计划着把 m 条道路的其中一条变成原来长度的 2 倍,使得 Farmer John 可能会多走一点路。
    他们想知道,最多能让 Farmer John 多走多少路呢?

    输入

    第一行一个正整数 n,m,表示仓库个数和道路条数。
    接下来 m 行,每行三个正整数,表示每条双向道路的连接的仓库和该双向道路的长度。

    输出

    输出只有一行,表示最多能让 Farmer John 每天早上多走多少路。

    样例输入

    5 7
    2 1 5
    1 3 1
    3 2 8
    3 5 7
    3 4 3
    2 4 7
    4 5 2
    

    样例输出

    2
    

    提示

    一开始的最短路为1→3→4→5,长度为1+3+2=6。
    将连接3和4的边变为原来的两倍,3×2=6。
    改造后的图,最短路为1→3→5,长度为1+7=8。
    多走了8−6=2的路程,可以证明这是最大的答案。
    对于50%的数据,1≤n≤50。
    对于100%的数据,1≤n≤250,1≤m≤25000,1≤w≤106。
    保证没有重边。

    思路:

    邻接矩阵存图(用链式前向星+堆优化T了),先用迪杰斯特拉找最短路,记录长度sum,再暴力枚举每一条边,将其长度更改为2倍后用迪杰斯特拉找最短路,后恢复这条边的长度,取最大长度与sum取差值即为结果。

    复杂度:  O(m*n²)优化后可变为O(m*n*logn)

    AC代码:

    O(m*n²)该超时,可不知道怎么就过了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL MAX=3e2;
    const LL MAX1=3e4;
    const LL INF=0x3f3f3f3f;
    LL n,m,k;
    LL dis[MAX+5];
    LL a[MAX+5][MAX+5];
    bool vis[MAX+5];
    
    void diji(LL s)
    {
        for(int i=1;i<=n;i++){
            dis[i]=a[s][i]; ///dis数组记录1点到该点的长度
            vis[i]=false;
        }
        vis[s]=true;
        while(1){
            LL k=-1,len=INF;
            for(LL i=1;i<=n;i++){
                if(!vis[i]&&len>dis[i]){
                    len=dis[i];
                    k=i;
                }
            }
            if(k==-1){
                break;
            }
            vis[k]=true;
            for(LL i=1;i<=n;i++){
                if(!vis[i]&&dis[i]>dis[k]+a[k][i]){
                    dis[i]=dis[k]+a[k][i];
                }
            }
        }
    }
    
    struct node{
        LL u,v,w;
    }edge[MAX1+5];
    int main()
    {
        scanf("%lld%lld",&n,&m);
        for(LL i=1;i<=n;i++){
            for(LL j=1;j<=n;j++){ ///邻接矩阵要初始化
                if(i==j) a[i][j]=0;
                else a[i][j]=INF;
            }
        }
        for(LL i=0;i<m;i++){
            LL u,v,w;
            scanf("%lld%lld%lld",&u,&v,&w);
            edge[i].u=u,edge[i].v=v,edge[i].w=w;
            a[u][v]=w;
            a[v][u]=w;
        }
        diji(1);
        LL sum=dis[n],maxx=-INF;
        for(int i=0;i<m;i++){
            LL u,v,w;
            u=edge[i].u,v=edge[i].v,w=edge[i].w; ///修改边长后恢复长度
            a[u][v]=2*w;
            a[v][u]=2*w;
            diji(1);
            maxx=max(maxx,dis[n]);
            a[u][v]=w;
            a[v][u]=w;
        }
        printf("%lld
    ",maxx-sum);
        return 0;
    }
    
  • 相关阅读:
    小程序教程3
    小程序教程2
    小程序教程1
    sublime介绍常用插件和快捷键
    ionic1跨域问题
    上传文件到windows server, 导出文件到linux, 打包压缩
    windows远程管理服务winrm
    windows配置ssh服务
    前端:websocket脚本
    前端实现: 抓拍和定时弹出任务
  • 原文地址:https://www.cnblogs.com/ldu-xingjiahui/p/12407422.html
Copyright © 2020-2023  润新知