传送门:ATC
正文:
初解此题,先用弗洛伊德跑了一遍最短路,然后再判断两点之间的距离C是否大于两点之间的最短路,如果大于,则这条边一定可以remove。但是,我不知道如何解决距离C正好等于两点之间最短路的情况。
此题妙就妙在判断等于的情况,我们可以把等于的情况分成两个部分:
1,该边正好是两点之间的唯一最短路,如果是这种情况,则该边不能删。
2,该边不是唯一最短路,即存在另外一条链,该链顶点数>=3,则该边可以删除。
那么我们该如何判断这条边是属于情况1还是情况2呢?
我们可以通过判断这两点(u,v)可不可以通过另外一点 o (o!=u 且 o!=v),使得 ,如果存在,则说明属于情况2,该边可以删。
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n ,m ;
cin>>n>>m;
vector<vector<ll>>dis(n,vector<ll>(n,1e18));
vector<tuple<int,int,int>>v;
for(int i = 0; i < m ;i ++){
int a , b , c;
cin>>a>>b>>c;
a--;b--;
dis[a][b] = dis[b][a] = c;
v.emplace_back(make_tuple(a,b,c));
}
for(int k = 0 ;k < n;k++){
for(int i = 0; i < n ; i++){
for(int j = 0; j < n ; j ++){
dis[i][j] = min(dis[i][j] , dis[i][k] + dis[k][j]);
}
}
}
int ans = 0;
for(auto [a,b,c] : v){
for(int i = 0 ;i < n ; i++){
if(dis[a][i] + dis[i][b] <= c){
ans++;
break;
}
}
}
cout<<ans<<'\n';
return 0;
}