标签:
Description
One day, Tom traveled to a country named BGM. BGM is a small country, but there are N (N <= 100) towns in it. Each town products one kind of food, the food will be transported to all the towns. In addition, the trucks will always take the shortest way. There are M (M <= 3000) two-way roads connecting the towns, and the length of the road is 1.
Let SUM be the total distance of the shortest paths between all pairs of the towns. Please write a program to calculate the new SUM after one of the M roads is destroyed.
Input
The input contains several test cases.
The first line contains two positive integers N, M. The following M lines each contains two integers u, v, meaning there is a two-way road between town u and v. The roads are numbered from 1 to M according to the order of the input.
The input will be terminated by EOF.
Output
Output M lines, the i-th line is the new SUM after the i-th road is destroyed. If the towns are not connected after the i-th road is destroyed, please output “INF” in the i-th line.
Sample Input
5 4
5 1
1 3
3 2
5 4
2 2
1 2
1 2
Sample Output
INF
INF
INF
INF
2
2
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <queue>
using namespace std;
const int N = 105;
const int M = 20005;
const int INF = 0x3f3f3f3f;
typedef long long ll;
int n, m, cnt;
int Dis[N];
struct Edge{
int from, to, flag;
};
struct HeapNode{
int d,u;
bool operator < (const HeapNode& rhs) const{
return d > rhs.d;
}
};
struct Dijkstra{
int n,m; //点数和边数
vector<Edge> edges; //边列表
vector<int> G[M]; //每个结点出发的边编号(从0开始编号)
vector<int> tree[M];
bool done[N]; //是否已永久标号
int d[N]; //s到各个点的距离
int p[N]; //最短路中的上一条边
void init(int n) {
this->n = n;
for(int i = 0; i < 2 * m; i++) {
G[i].clear();//清空邻接表
tree[i].clear();
}
memset(p, -1, sizeof(p));
edges.clear();//清空边表
}
void addEdge(int from, int to) {
//如果是无向图,每条无向边需调用两次AddEdge
edges.push_back((Edge){from, to, 0});
edges.push_back((Edge){to, from, 0});
m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
int dijkstra(int s) { //求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.flag) continue; //判断该边是否被删除
if(d[e.to] > d[u] + 1){
d[e.to] = d[u] + 1;
p[e.to] = G[u][i];
Q.push((HeapNode){d[e.to], e.to});
}
}
}
int sum = 0;
for (int i = 1; i <= n; i++) { //求最短路径的边和
if (i == s) continue;
if (d[i] == INF) return -1;
sum += d[i];
}
return sum;
}
void getTree(int s) {
for (int i = 1; i <= n; i++) {
if (i == s || p[i] == -1) continue;
tree[p[i]].push_back(s);
}
}
void killEdge(int x) {
edges[x].flag = 1;
edges[x^1].flag = 1;
}
void recoverEdge(int x) {
edges[x].flag = 0;
edges[x^1].flag = 0;
}
}dij;
void input() {
int a, b;
for (int i = 0; i < m; i++) {
scanf("%d %d", &a, &b);
dij.addEdge(a, b);
}
}
void solve() {
memset(Dis, 0, sizeof(Dis));
int sum = 0;
for (int i = 1; i <= n; i++) {
Dis[i] = dij.dijkstra(i); //Dis记录以i为起点的最短路边之和,即d数组之和
if (Dis[i] == -1) {
sum = -1;
break;
}
sum += Dis[i];
dij.getTree(i);
}
if (sum == -1) { //原始图已不联通,可以直接pass了
for (int i = 0; i < m; i++) {
printf("INF\n");
}
return;
}
int temp;
for (int i = 0; i < dij.edges.size(); i++) { //因为是双向边,所以正反都要考虑。
dij.killEdge(i); //杀死第i条边
if (i % 2 == 0) temp = sum; //正向边时,将原始的边和赋给temp
for (int j = 0; j < dij.tree[i].size(); j++) { //遍历最短路径上有第i条边的最短路径的起点
if (temp == -1) break;
temp -= Dis[dij.tree[i][j]]; //减去以tree[i][j]为起点的最短路径之和
int tft = dij.dijkstra(dij.tree[i][j]);
if (tft == -1) { //删除一边之后,图不连通
temp = -1;
break;
}
temp += tft; //加上删去第i条边之后的,新的边和
}
if (i % 2) {
if (temp == -1) printf("INF\n"); //图不连通
else printf("%d\n", temp); //新的边和
}
dij.recoverEdge(i); //复活第i条边
}
}
int main() {
while (scanf("%d %d", &n, &m) == 2) {
dij.init(n);
input();
solve();
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不可转载。
标签:
原文地址:http://blog.csdn.net/llx523113241/article/details/47732163