题解:P11819 [PA 2019 Final] Floyd-Warshall
尝试刻画这个错误的 floyd 能得到哪些路径,发现其实没有那么复杂,还是刻画得出来的。
下面约定
假设现在最外层枚举到
注意这是一个递归的结论。可以归纳出,所有
其中,
也就是说,所有被考虑的从
这是一个非常好的结论,以至于我们可以直接利用它来求出错误的最短路。
首先枚举
时间复杂度为
下面是代码
#include<bits/stdc++.h>
using namespace std;
const int N=2222;
int n,m,D[N],t[N],o[N],p;
vector<pair<int,int> >e[N],g[N];
void dij(vector<pair<int,int> >*E,int S,int L,int*s){
for(int i=1;i<=n;i++) o[i]=s[i]=1e9;
priority_queue<pair<int,int> >q;
for(q.push({s[S]=0,S});q.size();){
int x=q.top().second;
q.pop();
if(o[x]<1e9) continue;
o[x]=s[x];
for(auto[i,v]:E[x]) if(i<=L||x<=L) if(s[i]>v+s[x]) q.push({-(s[i]=v+s[x]),i});
}
for(int i=1;i<=n;i++) for(auto[j,v]:E[i]) s[j]=min(s[j],o[i]+v);
for(int i=L+1;i<=n;i++) for(auto[j,v]:E[i]) if(j>i) s[j]=min(s[j],s[i]+v);
}
int main(){
cin>>n>>m;
for(int i=1,j,k,l;i<=m;i++){
scanf("%d %d %d",&j,&k,&l);
e[j].push_back({k,l});
g[k].push_back({j,l});
}
for(int i=1;i<=n;i++){
dij(e,i,n,D);
dij(e,i,i,t);
for(int j=i+1;j<=n;j++) p+=t[j]!=D[j];
}
for(int i=1;i<=n;i++){
dij(g,i,n,D);
dij(g,i,i,t);
for(int j=i+1;j<=n;j++) p+=t[j]!=D[j];
}
cout<<p;
}