訓練指南 UVALive - 4080(最短路Dijkstra + 邊修改 + 最短路樹)
阿新 • • 發佈:2019-02-02
連通 列表 struct tle 枚舉 有用 tin ++ pro
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; }
訓練指南 UVALive - 4080(最短路Dijkstra + 邊修改 + 最短路樹)