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

时间:2022-12-15 07:11:27

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;
}