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

来源:互联网 发布:期货库存数据是什么 编辑:程序博客网 时间:2024/05/21 17:24

题目链接

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 1e9using 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;}
0 0