题意:给出n个点,m条边,在保持任意两点之间最短路径距离不变的情况下,最多可以去除多少边?
思路:在输入数据的时候,可以去除一些边,因为我们只需要两个点之间距离最小的那条边,然后跑一遍Floyd算法,求出任意两点的最短路,如果两个点是直接相连,并且被松弛过,或者松弛之后的距离与两点直接相连的距离相等,我们就可以去除这条两点之间直接相连的边。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<string>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<algorithm>
#define MAX 105
#define INF 0x3f3f3f3f
#define MOD 1000000007
using namespace std;
typedef long long ll;
int e[MAX][MAX];
int ee[MAX][MAX];
int cnt[MAX][MAX];
int is[MAX][MAX];
int main(void)
{
int t,n,m,i,j,k;
scanf("%d",&t);
int cas = 0;
while(t--){
int n,m;
scanf("%d%d",&n,&m);
memset(cnt,0,sizeof(cnt));
memset(is,0,sizeof(is));
memset(ee,0,sizeof(ee));
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(i == j){
e[i][j] = 0;
}
else{
e[i][j] = INF;
}
}
}
int ans = 0;
for(int i = 1; i <= m; i++){
int a,b,w;
scanf("%d%d%d",&a,&b,&w);
//保留最小的边的距离
e[a][b] = e[b][a] = min(e[a][b],w);
//记录两点之间边的数量
cnt[a][b]++;
cnt[b][a]++;
//记录两点之间是否有边相连
ee[a][b] = ee[b][a] = 1;
}
for(int i = 1; i <= n; i++){
for(int j = i + 1; j <= n; j++){
if(cnt[i][j] > 0){
//两点之间我们只需要那条最短边,其余的都舍去
ans += cnt[i][j] - 1;
}
}
}
for(int k = 1; k <= n; k++){
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(i == k){
continue;
}
if(j == k){
continue;
}
//标记被松弛的以及松弛之后距离与原来相等的
if(e[i][j] >= e[i][k] + e[k][j]){
e[i][j] = e[i][k] + e[k][j];
is[i][j] = is[j][i] = 1;
}
}
}
}
for(int i = 1; i <= n; i++){
for(int j = i + 1; j <= n; j++){
if(is[i][j] && ee[i][j]){
ans++;
}
}
}
printf("Case %d: %d\n",++cas,ans);
}
return 0;
}