给你n个点,m条双向边,每条边的长度都为1,求删去第i条边 后, 每个点到其他点的最短路的距离之和.
//题意很不清晰
网上有最短路spfa 和djskra 的做法, 而且代码可以ac, 但是代码是错的,只是刚好卡着时间过了
由于每条边的长度都一样, 而且根据答案我们可以得出, 每一个点到其他点的距离之和 应该是一棵树,所以我们要求n棵最短路树的和,所以先预处理记录每个点为原点的最短路树之和, 所以正解应该是bfs + 最短路树
做法:
先对每一个点都进行一次bfs, 计算出每个点到其他点的距离之和, 如果无法bfs到所有的点说明不连通,那么可以直接打印INF;
在预处理时, 我们可以先做一个操作,在bfs的时候,对每一个点以某个点为原点进行bfs时候的前驱进行记录,方便 我们后面 进行判断要删除的边是否在 我们之前bfs过的最短路树上,
题目还会出现重边的情况, 那么如果删除的边是 重边的话,那么其实答案不会发生变化, 不用进行处理, 要删去的边如果没在最短路树上的话 也不用进行处理,答案没有变化。
/*
Algorithm:
Author: anthony1314
Creat Time:
Time Complexity:
*/
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<cstring>
#include<cstdio>
//#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define mod 1e9 + 7
#define line printf("--------------");
using namespace std;
#define inf 0x3f3f3f3f
int mapp[105][105];
bool vis[105];
int sum[3005];
int pre[105][105];
int dis[105];
struct node {
int end;
int first;
} edge[3005];
int n, m;
int bfs(int k, bool flag) {
memset(vis, false, sizeof(vis));
memset(dis, 0, sizeof(dis));
int cnt = 1, summ = 0;
queue<int> que;
while(!que.empty()) {
que.pop();
}
vis[k] = true;
que.push(k);
while(!que.empty()) {
int s = que.front();
que.pop();
for(int i = 1; i <= n; i++) {
if(!vis[i] && mapp[i][s] > 0) {
if(flag) { // 记录第一次bfs时 每个点的前驱 方便后面进行判断
pre[k][i] = s;//以k为源点 i的前驱为s
}
dis[i] = dis[s] + 1;
summ += dis[i];
vis[i] = true;
que.push(i);
cnt++;
}
}
}
if(cnt != n) {//访问的点不到n个说明不连通
return -1;
} else {
return summ;
}
}
int main() {
while(~scanf("%d %d", &n, &m)) {
memset(mapp, 0, sizeof(mapp));
memset(pre, 0, sizeof(pre));
memset(sum, 0, sizeof(sum));
int x, y;
for(int i = 0; i < m; i++) {
scanf("%d %d", &x, &y);
mapp[x][y]++;
mapp[y][x]++;
edge[i].first = x;
edge[i].end = y;
}
int k;
int summ = 0;
for(k = 1; k <= n; k++) {
int ans = bfs(k, true);
if(ans == -1) {//没删边之前就不连通
break;
}
sum[k] = ans;
summ += ans;
}
if(k <= n) {
for(int i = 0; i < m; i++) {
puts("INF");
}
continue;
}
for(int i = 0; i < m; i++) {
int x = edge[i].first, y = edge[i].end;
if(mapp[x][y] > 1) {//重边 无影响
printf("%d\n", summ);
continue;
}
int sum1 = 0, s1;
for(int j = 1; j <= n; j++) {
if(pre[j][x] == y || pre[j][y] == x) { //如果 x-y 都在 第j颗bfs最短路树上 就需要重新进行计算
mapp[x][y] = 0;
mapp[y][x] = 0;//删除边
s1 = bfs(j, false);
if(s1 == -1) {
mapp[x][y]++;
mapp[y][x]++;//不连通
sum1 = -1;
break;
}
sum1 += s1;
mapp[x][y]++;
mapp[y][x]++;
} else {
sum1 += sum[j];
}
}
if(sum1 == -1) { //不连通
puts("INF");
} else {
cout<<sum1<<endl;
}
}
}
return 0;
}