UVa 1416 - Warfare And Logistics (最短路树)
题目链接:https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=0&problem=4162&mosmsg=Submission+received+with+ID+26583689
题目要求所有点对间的最短路之和,因为是稀疏图,floyd 和 dijstra 差不多,如果枚举 m 条边每次求一遍答案,时间无法承受
考虑最短路树,如果源点确定,那么只有修改在最短路树上的边,才会改变源点到其他点的最短距离,而这样的边只有 \(n-1\) 条
所以枚举所有在最短路树上的边即可,要注意的细节就是因为是无向图,删边时要将反向边也删掉
时间复杂度 \(O(n^2mlogn)\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 110;
const int INF = 0x3f3f3f3f;
int n, m, L;
int u[1010], v[1010], w[1010];
int h[maxn], cnt = 1;
struct E{
int from, to, cost, next;
}e[maxn * 10 * 2];
void add(int u, int v, int w){
e[++cnt].to = v;
e[cnt].from = u;
e[cnt].cost = w;
e[cnt].next = h[u];
h[u] = cnt;
}
ll ans1, ans2[3010];
int d[maxn], pre[maxn], vis[3010];
void dij(int S, int ban){
memset(pre, 0, sizeof(pre));
memset(d, 0x3f, sizeof(d));
d[S] = 0;
priority_queue<pii, vector<pii>, greater<pii> > q;
q.push(pii(d[S], S));
while(!q.empty()){
pii p = q.top(); q.pop();
int u = p.second;
if(p.first != d[u]) continue;
for(int i = h[u] ; i != -1 ; i = e[i].next){
int v = e[i].to;
if(i == ban || i == (ban ^ 1)) continue;
if(d[v] > d[u] + e[i].cost){
pre[v] = i;
d[v] = d[u] + e[i].cost;
q.push(pii(d[v], v));
}
}
}
}
void solve(int u){
int res1 = 0;
dij(u, -1); // 求出最短路树
for(int i = 1 ; i <= n ; ++i){
ans1 += d[i] == INF ? L : d[i];
}
for(int i = 1 ; i <= n ; ++i){ // 枚举删除哪条边
if(!pre[i]) continue;
vis[pre[i]] = 1;
}
}
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
while(scanf("%d%d%d", &n, &m, &L) == 3){
ans1 = 0;
memset(ans2, 0, sizeof(ans2));
memset(vis, 0, sizeof(vis));
memset(h, -1, sizeof(h)); cnt = 1;
for(int i = 1 ; i <= m ; ++i){
scanf("%d%d%d", &u[i], &v[i], &w[i]);
add(u[i], v[i], w[i]); add(v[i], u[i], w[i]);
}
for(int i = 1 ; i <= n ; ++i){
solve(i);
}
for(int i = 2 ; i <= cnt ; i += 2){
if(vis[i] || vis[i^1]){
for(int j = 1 ; j <= n ; ++j){
dij(j, i);
for(int k = 1 ; k <= n ; ++k){
ans2[i] += d[k] == INF ? L : d[k];
}
}
}
}
ll res2 = 0;
for(int i = 1 ; i <= cnt ; ++i) res2 = max(res2, ans2[i]);
printf("%lld %lld\n", ans1, res2);
}
return 0;
}