题目链接:http://acm.fzu.edu.cn/problem.php?pid=2271
题意:
保存没删边之前,每个点到其他点的最短路径所用到的所有边,求出没保存的边有几个;
思路:因为两点之间可能会有多条路,所以我们要留下两点之间最短的边,然后删去其他边;之后,在用Folyd去松弛任意两点之间的距离,只要这两个点是存在边的,而且能够松弛成更短的距离,那么原有的那条边就可以删去,这里要注意,可能会存在自环的情况,自环的边无疑是多余的,可以删去的;下面给出代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int Maxn = 110;
const int INF = 0x3f3f3f3f;
int tmp[Maxn][Maxn],a[Maxn][Maxn];
bool vis[Maxn][Maxn];
int main (void)
{
int t,N,M,u,v,w;
scanf("%d",&t);
for (int cas = 1; cas <= t; ++cas) {
scanf("%d%d",&N,&M);
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= N; ++j) {
tmp[i][j] = INF; //初始化
}
}
int ans = 0;
for (int i = 1; i <= M; ++i) {
scanf("%d%d%d",&u,&v,&w);
if(tmp[u][v] != INF) ans++; // 一般点与点之间的距离初始化时自己到自己应该为0
// 因为考虑到可能有自环的情况,如果存在自环,那这条边也应该删去
//这里统一为INF,就不用再而外判断是不是为自环了
tmp[u][v] = tmp[v][u] = min(tmp[u][v],w);
}
memcpy(a,tmp,sizeof(a));
memset(vis,0,sizeof(vis));
for (int k = 1; k <= N; ++k)
for (int i = 1; i <= N; ++i)
for (int j = 1; j <= N; ++j) {
if(i == j) continue; // 自己到自己不用松弛
// 如果存在松弛前后相等的话,可以把原来的那条边删去,用松弛的边
if(tmp[i][k] != INF && tmp[k][j] != INF && tmp[i][j] >= tmp[i][k]+tmp[k][j]) {
tmp[i][j] = tmp[i][k]+tmp[k][j];
vis[i][j] = true;
}
}
for (int i = 1; i < N; ++i)
for (int j = i+1; j <= N; ++j) {
if(a[i][j] == INF) continue;// 如果i,j之间本身就没边,那么就不用做处理,一般没边也是能够松弛的
//只要tmp[i][k]和tmp[k][j]有边的话;
if(a[i][j] >= tmp[i][j] && vis[i][j]) ans++;
}
printf("Case %d: %d\n",cas,ans);
}
return 0;
}