bzoj 1491 [NOI2007]社交网络
Floyd
在之前原有的记录最短路的数组f[i][j]之外,再记录一个数组g[i][j]表示从点i到点j的最短路路径数量
当转移时枚举的中间节点k,只要f[i][j]被更新,g[i][j]被重置为f[i][k]*f[k][j]
那当f[i][j]==f[i][k]+f[k][j]时g[i][j]累加通过中间节点k的最短路数量f[i][k]*f[k][j]
最后枚举每一个点(i),只要其他两点(j,k)到此点的最短路之和等于这两点的最短路,即f[j][i]+f[i][k]==f[j][k]
那么说明这一点是(j,k)两点最短路可以经过的点,所以累加答案
还有在做Floyd的时候要注意i,j,k三点不能重复,否则会重复累加答案
#include <bits/stdc++.h> #define ll long long #define inf 1e18 using namespace std; ll n,m,mp[110][110],g[110][110]; ll f[110][110]; double ans[110]; int main() { scanf("%lld%lld",&n,&m); for (ll i=1;i<=n;i++) { for (ll j=1;j<=n;j++) { f[i][j]=inf; } f[i][i]=0; } for (ll i=1;i<=m;i++) { ll u,v,len; scanf("%lld%lld%lld",&u,&v,&len); f[u][v]=len; f[v][u]=len; g[u][v]=1; g[v][u]=1; } for (ll k=1;k<=n;k++) { for (ll i=1;i<=n;i++) { if (i==k) continue; for (ll j=1;j<=n;j++) { if (i==j && j==k)//注意 continue; if (f[i][j]>f[i][k]+f[k][j]) { f[i][j]=f[i][k]+f[k][j]; g[i][j]=g[i][k]*g[k][j];//覆盖 } else if (f[i][j]==f[i][k]+f[k][j]) { g[i][j]+=g[i][k]*g[k][j];//累加 } } } } for (ll i=1;i<=n;i++) { for (ll j=1;j<=n;j++) { if (j==i) continue; for (ll k=1;k<=n;k++) { if (k==i || k==j) continue; if (f[j][k]==f[j][i]+f[i][k]) ans[i]+=(g[j][i]*g[i][k]*1.0)/(g[j][k]*1.0);//累加答案 } } } for (ll i=1;i<=n;i++) printf("%.3lf\n",ans[i]); }