题目描述
一个无向图,有 N 个点,
M 条边。无向图保证是联通图。记 dis[i][j] 表示结点 i 到结点j 的最短路径。记 sum 为所有 dis[i][j] 的总和,其中 1≤i≤N , 1≤j≤N 。
假如删除某条边后,能使得 sum 增加,那么该边就是“重要边”。注意:如果删除某条边后,某结点 i 和结点j 不联通了,那么 dis[i][j]=dis[j][i]=∞ 。
还有一个注意的地方:这里的删除边只是假设删除,纯粹是为了计算该边是否是“重要边”,并不是真的删除。
输入格式 1724.in
第一行,两个整数。 N 和
M 。 1≤N≤300 , 1≤M≤3000 。
接下来有 M 行,每行两个整数:a , b ,表示结点a 和 b 之间有一条长度是1的双向边。1≤a,b≤N 。
输出格式 1724.out
从小到大输出所有“重要边”的序号。其中边的序号是根据输入数据的次序从1至 M 进行编号的。
输入样例 1724.in
4 6
1 2
2 3
3 4
1 4
1 3
4 1
输出样例 1724.out
1
2
3
5
数据范围
对于20%的数据,
1≤N≤50 , 1≤M≤1000
这题有点坑,一开始我还想着先跑 Floyd 维护任意两点距离,枚举去掉的边,再用类似 SPFA 的方法修改它们会影响到的点。然而其实并不需要。
后来我根据样例想了一种神奇的水法:统计重边。如果有重边,那么相同的这些边都不是重要边,剩下的就都是重要边。一交居然 AC 了。仔细想想,其实不难证明。
考虑到每条边的长度固定为1,我们知道,对于任意点对 (x,y) ,他们的距离会被修改,当且仅当之前的最短路当中经过的边被删去,或他们之前没有边相连,而现在直接连了一条边。此题当中只有删边,因此不用考虑后一种情况。
而且我们知道,删边是分别单独进行的,因此只需分两类讨论:对于有重边的边,将其去掉之后不会受到任何影响;对于单独的边
(x,y)
,去掉之后,结点
x
和
参考代码:
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 300 + 10;
const int maxm = 3e3 + 10;
int n, m;
int a[maxm], b[maxm];
int g[maxn][maxn];
int main(void) {
freopen("1724.in", "r", stdin);
freopen("1724.out", "w", stdout);
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++) {
scanf("%d%d", &a[i], &b[i]);
++g[min(a[i], b[i])][max(a[i], b[i])];
}
for (int i = 0; i < m; i++)
if (g[min(a[i], b[i])][max(a[i], b[i])] == 1) printf("%d\n", i + 1);
return 0;
}