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