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
",ans[i]);
}
原文地址:https://www.cnblogs.com/huangchenyan/p/11188568.html