[BZOJ 1491][NOI 2007]社交网络(Floyd+计数问题)

题目链接

http://www.lydsy.com/JudgeOnline/problem.php?id=1491

思路

题面中的定义式非常像floyd的DP方程,而且数据范围也能过 O(n3) ,显然这个题可以用类似floyd的方法来搞。。。
做两遍floyd,第一遍求出多源最短路,以及任意两点间最短路的方案数,这个比较好求,然后第二遍就是枚举点 k ,求出点 k 的答案,枚举 ij 的最短路,判断 k 是否在这条最短路上,将 ij 的最短路对最终答案的贡献加进去即可。
注意最终要么将任意的点 ii 的最短路数赋为1,要么在累加贡献时,除开点 ii 的最短路对最终答案的贡献。

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXN 110
#define INF 1e9

using namespace std;

int n,m;
double map[MAXN][MAXN];
double a[MAXN][MAXN]; //a[i][j]=i到j的最短路径条数
double ans[MAXN];

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            map[i][j]=INF;
    for(int i=1;i<=m;i++)
    {
        int u,v;
        double w;
        scanf("%d%d%lf",&u,&v,&w);
        map[u][v]=map[v][u]=w;
        a[u][v]=a[v][u]=1;
    }

    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                if(map[i][k]+map[k][j]<map[i][j])
                {
                    map[i][j]=map[i][k]+map[k][j];
                    a[i][j]=a[i][k]*a[k][j]; //i到j的距离发生变化后,路径数也会跟着重置
                }
                else if(map[i][k]+map[k][j]==map[i][j]) //有相同的路径i->k->j,加法计数统计i->j的路径数
                    a[i][j]+=a[i][k]*a[k][j];
            }
    for(int i=1;i<=n;i++) a[i][i]=0;
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(map[i][k]+map[k][j]==map[i][j]&&a[i][j]>0) //k在i到j的最短路径上
                    ans[k]+=a[i][k]*a[k][j]/a[i][j]; //和题面上的式子其实是一样的
    for(int i=1;i<=n;i++)
        printf("%.3lf\n",ans[i]);
    return 0;
}

你可能感兴趣的:([BZOJ 1491][NOI 2007]社交网络(Floyd+计数问题))