训练指南 UVALive - 4080(最短路Dijkstra + 边修改 + 最短路树)



layout: post
title: 训练指南 UVALive - 4080(最短路Dijkstra + 边修改 + 最短路树)
author: "luowentaoaa"
catalog: true
mathjax: true
tags:
- Dijkstra
- 最短路树
- 图论
- 训练指南


Warfare And Logistics

UVALive - 4080

题意

①先求任意两点间的最短路径累加和,其中不连通的边权为L ②删除任意一条边,求全局最短路径和的最大值

题解

刚看到题目是让各点之间的最短路径和,所以立马想到啦floyd算法求最短路,然后发现还要去掉一条边后求最短路中的最大值,则floyd会超时,所以打算用dijkstra+堆优化做,首先枚举n个顶点求各个顶点之间的最短路径,并求出最短路树,然后枚举每条边,如果这条边在最短路树中,则再求一遍该点的最短路径即可,如果不在最短路树中,则直接利用第一次求得最短路即可。

所谓的最短路树是指在求最短路的同时,记录最短路径并且标记那些点之间的连线有用到。

如果在枚举某个作为起点的时候这删去的点没有用到那就直接加上答案即可,这样时间就省去了一个m

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
const int maxn=100+10;
const int inf=1000000000;
struct Edge{
    int from,to,dist;
};
struct HeapNode{
    int d,u;
    bool operator <(const HeapNode& rhs)const{
        return d>rhs.d;
    }
};
struct Dijkstra{
    int n,m;              ///点数和边数  点编号0~N-1
    vector<Edge>edges;    ///边列表
    vector<int>G[maxn];   ///每个节点出发的边编号
    bool done[maxn];      /// 是否已永久标号
    int d[maxn];          /// s到各个点的距离
    int p[maxn];          /// 最短路中的上一条边

    void init(int n){
        this->n=n;
        for(int i=0;i<n;i++)G[i].clear();
        edges.clear();
    }
    void AddEdge(int from,int to,int dist){ ///无向图调用两次
        edges.push_back((Edge){from,to,dist});
        m=edges.size();
        G[from].push_back(m-1);
    }
    void dijkstra(int s){
        priority_queue<HeapNode>Q;
        for(int i=0;i<n;i++)d[i]=inf;
        d[s]=0;
        memset(done,0,sizeof(done));
        Q.push((HeapNode){0,s});
        while(!Q.empty()){
            HeapNode x=Q.top();Q.pop();
            int u=x.u;
            if(done[u])continue;
            done[u]=true;
            for(int i=0;i<G[u].size();i++){
                Edge& e=edges[G[u][i]];
                if(e.dist>0&&d[e.to]>d[u]+e.dist){
                    d[e.to]=d[u]+e.dist;
                    p[e.to]=G[u][i];
                    Q.push((HeapNode){d[e.to],e.to});
                }
            }
        }
    }
};

Dijkstra solver;
int n,m,L;
vector<int>gr[maxn][maxn];
int used[maxn][maxn][maxn];
int idx[maxn][maxn];
int sum_single[maxn];

int compute_c(){
    int ans=0;
    memset(used,0,sizeof(used));
    for(int src=0;src<n;src++){
        solver.dijkstra(src);
        sum_single[src]=0;
        for(int i=0;i<n;i++){
            if(i!=src){
                int fa=solver.edges[solver.p[i]].from;
                used[src][fa][i]=used[src][i][fa]=1;
            }
            sum_single[src]+=(solver.d[i]==inf?L:solver.d[i]);
        }
        ans+=sum_single[src];
    }
    return ans;
}
int compute_newc(int a,int b){
    int ans=0;
    for(int src=0;src<n;src++)
        if(!used[src][a][b])ans+=sum_single[src];
        else{
            solver.dijkstra(src);
            for(int i=0;i<n;i++)
                ans+=(solver.d[i]==inf?L:solver.d[i]);
        }
    return ans;
}
int main()
{
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    while(cin>>n>>m>>L){
        solver.init(n);
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)gr[i][j].clear();
        for(int i=0;i<m;i++){
            int a,b,s;
            cin>>a>>b>>s;a--;b--;
            gr[a][b].push_back(s);
            gr[b][a].push_back(s);
        }
        for(int i=0;i<n;i++)
        for(int j=i+1;j<n;j++)if(!gr[i][j].empty()){
            sort(gr[i][j].begin(),gr[i][j].end());
            solver.AddEdge(i,j,gr[i][j][0]);
            idx[i][j]=solver.m-1;
            solver.AddEdge(j,i,gr[i][j][0]);
            idx[j][i]=solver.m-1;
        }
        int c=compute_c();
        int c2=-1;
        for(int i=0;i<n;i++)
        for(int j=i+1;j<n;j++)if(!gr[i][j].empty()){
            int &e1=solver.edges[idx[i][j]].dist;
            int &e2=solver.edges[idx[j][i]].dist;
            if(gr[i][j].size()==1)e1=e2=-1;
            else e1=e2=gr[i][j][1];
            c2=max(c2,compute_newc(i,j));
            e1=e2=gr[i][j][0];
        }
        cout<<c<<" "<<c2<<endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/luowentao/p/10347356.html

时间: 2024-08-26 16:06:37

训练指南 UVALive - 4080(最短路Dijkstra + 边修改 + 最短路树)的相关文章

训练指南 UVALive - 4043(二分图匹配 + KM算法)

layout: post title: 训练指南 UVALive - 4043(二分图匹配 + KM算法) author: "luowentaoaa" catalog: true mathjax: true tags: - 二分图匹配 - 图论 - 训练指南 Ants UVALive - 4043 题意 给你n个白点和n个黑点的平面坐标,要求用n条不相交的线连起来,每条线段连一个白点和黑点,每个点连一条线,也就是匹配.让你输出第i个白点所对应的黑点. 思路 二分图完美匹配问题.但是题目

训练指南 UVALive - 3415(最大点独立集)

layout: post title: 训练指南 UVALive - 3415(最大点独立集) author: "luowentaoaa" catalog: true mathjax: true tags: - 二分图 - 图论 - 训练指南 Guardian of Decency UVALive - 3415 我们将男女分开来 就可以建出一个二分图,对于任意的男女生 只要上边四个条件一个也不满足 就表示不能同时去 ,那么我们在其中间连一条边,那么最终的结果就是我们从中取出尽量多的点,

训练指南 UVALive - 3126(DAG最小路径覆盖)

layout: post title: 训练指南 UVALive - 3126(DAG最小路径覆盖) author: "luowentaoaa" catalog: true mathjax: true tags: - 二分图 - 图论 - 训练指南 - 最小路径覆盖 Taxi Cab Scheme UVALive - 3126 题目大意:n个客人,从城市的不同位置出发,到达他们的目的地.已知每个人的出发时间hh:mm,出发地点(x1,y1)及目的地(x2,y2),要求使用最少的出租车接

训练指南 UVA - 11374(最短路Dijkstra + 记录路径 + 模板)

layout: post title: 训练指南 UVA - 11374(最短路Dijkstra + 记录路径 + 模板) author: "luowentaoaa" catalog: true mathjax: true tags: - 最短路 - Dijkstra - 图论 - 训练指南 Airport Express UVA - 11374 题意 机场快线有经济线和商业线,现在分别给出经济线和商业线的的路线,现在只能坐一站商业线,其他坐经济线,问从起点到终点的最短用时是多少,还有

训练指南 UVA - 10917(最短路Dijkstra + 基础DP)

layout: post title: 训练指南 UVA - 10917(最短路Dijkstra + 基础DP) author: "luowentaoaa" catalog: true mathjax: true tags: - 最短路 - 基础DP - Dijkstra - 图论 - 训练指南 Walk Through the Forest UVA - 10917 题意 Jimmy打算每天沿着一条不同的路走,而且,他只能沿着满足如下条件的道路(A,B):存在一条从B出发回家的路径,比

训练指南 UVA - 11090(最短路BellmanFord+ 二分判负环)

layout: post title: 训练指南 UVA - 11090(最短路BellmanFord+ 二分判负环) author: "luowentaoaa" catalog: true mathjax: true tags: - 最短路 - 基础DP - BellmanFord - 图论 - 训练指南 Going in Cycle!! UVA - 11090 题意 就最小的环的平均权值 题解 分枚举平均值mid,只需判断是否存在平均值小于mid的回路,即判断是否有sum(wi)&

训练指南 UVA - 11478(最短路BellmanFord+ 二分+ 差分约束)

layout: post title: 训练指南 UVA - 11478(最短路BellmanFord+ 二分+ 差分约束) author: "luowentaoaa" catalog: true mathjax: true tags: - 最短路 - BellmanFord - 图论 - 训练指南 - 差分约束 Halum UVA - 11478 题意 带权有向图,每个点都可以有如下操作:令从ta出发的每一条边增加d,终止于ta的每一条边减小d 最后让所有边权的最小值非负且尽量大 题

UVALive 4080 Warfare And Logistics(Dijkstra+最短路树)

 题意:给定一个n节点m条边的无向图,定义c为每对顶点的最短路之和,要求删掉一条边重新求一个c值c',求出c'最大值. 思路:如果用floyd算法计算c,每尝试删除一条边都要重新计算一次,时间复杂度为O(n*n*n*m),很难承受.如果用n次Dijkstra计算单源最短路,时间复杂度味O(n*m*m*logn).虽然看上去比之前的好,但由于佛洛依德算法的常数很小,实际运行时间差不多.这时候,可以考虑最短路树.因为在源点确定的情况下,只要最短路树不被破坏,起点到所有点的距离都不会发生改变.也就

带权最短路 Dijkstra, SPFA, Bellman-Ford, ASP, Floyd-Warshall 算法分析

转载:https://www.renfei.org/blog/weighted-shortest-path.html 图论中,用来求最短路的方法有很多,适用范围和时间复杂度也各不相同. 本文主要介绍的算法的代码主要来源如下: Dijkstra: Algorithms(<算法概论>)Sanjoy Dasgupta, Christos Papadimitriou, Umesh Vazirani;<算法竞赛入门经典-训练指南>刘汝佳.陈峰. SPFA (Shortest Path Fas