题目描述
一个无向图,有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;
}