题意:有n个点,m条边,求依次删除每一条边后所有两点之间的最短路径的和。
思路:先以每一个顶点为源点求一遍最短路,这样就形成了n个最短路树,第i个树的边权和为sum[i]。然后枚举删除每一个边,分别以边上两点u、v为源点求最短路,如果u、v的距离发生变化,则以u为源点时,v节点下的子树的dis[i]都会变化,因边是双向的,i到u的距离也一样会发生改变(以v为源点时情况是一样的)。那么,以u、v为源点求最短路后生成树的边权和分别为num1和num2,总和的变化量为2×(num1 + num2) - 2×(sum[u] + sum[v]) - 2×(dis[u] - 1) 【因为u到v的边在之前算了4次,本来算2次就够了】
关键点:假设被删除的边出现在以a为源点的最短路树中,b在被删除边的两点中的某一点的子树中,则a也一定在b的最短路树中。
#include<cstdio>
#include<iostream>
#include<queue>
#include<functional>
#include<vector>
#include<algorithm>
#include<stack>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
typedef pair<int,int> P;
const int maxn = 105;
const int maxm = 3005;
const int inf = 1e9;
struct Edge{
int to,cost,tag;
};
int n,m;
vector<Edge> G[maxn];
int dis[maxn],sum[maxn];
int uu[maxm],vv[maxm];
priority_queue<P,vector<P>,greater<P> > que;
void init(){
memset(sum,0,sizeof(sum));
for(int i=0;i<maxn;i++) G[i].clear();
}
void add_Edge(int from,int to,int cost,int tag){
Edge e;
e.to = to;e.cost = cost;e.tag = tag;
G[from].push_back(e);
e.to = from;
G[to].push_back(e);
}
int dij(int s,int k){
fill(dis,dis+maxn,inf);
dis[s] = 0;
que.push(P(0,s));
while(!que.empty()){
P p = que.top();que.pop();
int v = p.second;
if(dis[v] != p.first) continue;
for(int i=0;i<G[v].size();i++){
Edge e = G[v][i];
if(e.tag == k) continue;
if(dis[e.to] > dis[v] + e.cost){
dis[e.to] = dis[v] + e.cost;
que.push(P(dis[e.to],e.to));
}
}
}
int res = 0;
for(int i=1;i<=n;i++){
//cout<<i<<" "<<dis[i]<<endl;
if(dis[i] != inf) res += dis[i];
else return inf;
}
return res;
}
int main(){
while(~scanf("%d%d",&n,&m)){
init();
for(int i=1;i<=m;i++){
scanf("%d%d",&uu[i],&vv[i]);
add_Edge(uu[i],vv[i],1,i);
}
int ans = 0;
for(int i=1;i<=n;i++){
sum[i] = dij(i,0);
//cout<<sum[i]<<endl;
if(sum[i] == inf){
ans = inf;
break;
}else ans += sum[i];
}
if(ans == inf){
while(m--) printf("INF\n");
}else{
for(int i=1;i<=m;i++){
int u = uu[i],v = vv[i];
int num1 = dij(u,i);
int num2 = dij(v,i);
//cout<<num1<<" "<<num2<<endl;
if(num1 == inf){
printf("INF\n");
continue;
}else printf("%d\n",ans + 2*num1 + 2*num2 - 2*sum[u] - 2*sum[v] - 2*dis[u] + 2);
}
}
}
return 0;
}