大意:
给定一张图,统计可删的边的总数,一条边当且仅当其对图的联通性和任意两点的最短路无影响时可以被删去。
思路:
大概会去往flyod方向上靠,因为这肯定是要求多源最短路的。大部分情况应该都是ok的,只要先建完一张最短路图,然后对于每一条边,只要它大于对应两条边的最短路,那么它就一定可以被删去。
但是还有一个问题,就是当这条边的权值和其对应两点的最短路一样长时,得分为两种情况
1:最短路就是这条边自身,那么它肯定是不能删的。
2.它对构成另一条最短路无贡献,那么它就是可以删的。
所以我们只要判断这条边对应的最短路是不是由它构成的即可。
奇妙的地方来了。因为情况一的最短路是只有一条边,而情况2有至少两条,也就是我们可以通过枚举中间点。如果枚举的中间点所对应的路的权值恰好等于对应两点最短路,那么这两点的对应边就一定可以删了。
code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n,m;
ll c[310][310];
ll a[310*310],b[310*310],z[310*310];
int main()
{
cin>>n>>m;
memset(c,0x3f,sizeof c);
for(int i=1;i<=m;++i)
{
cin>>a[i]>>b[i]>>z[i];
c[a[i]][b[i]]=z[i];
c[b[i]][a[i]]=z[i];
}
for(int k=1;k<=n;++k)
{
for(int i=1;i<=n;++i)
{
for(int j=1;j<=n;++j)
{
c[i][j]=min(c[i][j],c[i][k]+c[k][j]);
}
}
}
ll ans=0;
for(int i=1;i<=m;++i)//遍历所有边
{
for(int j=1;j<=n;++j)
{
if(c[a[i]][j]+c[j][b[i]]<=z[i])
{
ans++;
break;
}
}
}
cout<<ans<<endl;
return 0;
}