zoukankan      html  css  js  c++  java
  • 训练指南 UVALive


    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;
    }
    
  • 相关阅读:
    学习笔记 MYSQL报错注入(count()、rand()、group by)
    学习笔记 HTTP参数污染注入
    学习笔记 MSSQL显错手工注入
    代码审计入门后审计技巧
    字符串的排列
    二叉搜索树与双向链表
    复杂链表的复制
    二叉树中和为某一值的路径
    二叉搜索树的后序遍历序列
    从上往下打印二叉树
  • 原文地址:https://www.cnblogs.com/luowentao/p/10347356.html
Copyright © 2011-2022 走看看