luogu2047社交网络

题目


分析

  1. 此题很明显啊,要在跑最短路的同时把经过每个结点间的最短路给统计出来。起初不知道怎么做,那就看看数据范围吧。一看,好家伙,\(n < 100\)。这明摆着就是Foyld啊。
  2. 具体操作
    Folyd跑两点之间的最短路并且统计两点之间的最短路数量:
  • 如果\(f[i][j]\)大于\(f[i][k]+f[k][j]\),则我们更新\(i,j\)之间的最短路长度,然后\(i,j\)之间的最短路数等于\(i,k\)\(k,j\)的最短路乘积
  • 如果\(f[i][j]\)等于\(f[i][k]+f[k][j]\),则\(i,j\)之间的最短路数等于\(i,k\)\(k,j\)的最短路之和
    然后开始计算答案:
  • 如果中间点\(k\)等于两个端点,这不是合法的结果。
  • 如果\(a[i][k] + a[k][j] == a[i][j]\),说明\(k\)\(i,j\)的最短路上。\(edge[i][k]*edge[k][j]\)为经过\(k\)\(i,j\)之间的最短路数量。
    输出答案即可
    3.代码
#include <bits/stdc++.h>
using namespace std;

const int N = 110;
long long n,m,INF;
long long x,y,z;
long long a[N][N],edge[N][N];
double ans[N];

int main()
{
	cin >> n >> m;
	memset(a,0x7f,sizeof a);
	memset(edge,0,sizeof edge);
	INF = a[1][1];
	for(int i = 1;i <= m;i ++ )
	{
		cin >> x >> y >> z;
		a[x][y] = a[y][x] = z;
		edge[x][y] = edge[y][x] = 1;
	}

	for(int k = 1;k <= n;k ++ )
	{
		for(int i = 1;i <= n;i ++ )
		{
			for(int j = 1;j <= n;j ++ )
			{
				if(a[i][k] == INF && a[k][j] == INF) continue;
				if(a[i][j] > a[i][k] + a[k][j])
				{
					a[i][j] = a[i][k] + a[k][j];
					edge[i][j] = edge[i][k] * edge[k][j];
					continue;
				}
				if(a[i][j] == a[i][k] + a[k][j])
				{
					edge[i][j] += edge[i][k] * edge[k][j];
				}
			}
		}
	}

	for(int k = 1;k <= n;k ++ )
	{
		for(int i = 1;i <= n;i ++ )
		{
			for(int j = 1;j <= n;j ++ )
			{
				if(i == j || j == k || i == k) continue;
				if(a[i][k] + a[k][j] == a[i][j])
				{
					ans[k] += (1.0 * edge[i][k] * edge[k][j]) / edge[i][j];
				}
			}
		}
	}

	for(int i = 1;i <= n;i ++ )
	{
		printf("%0.3lf\n",ans[i]);
	}
	
	return 0;
}
  1. 这个题很好的让我理解了Folyd算法,也明白了中间点\(k\)的作用。事好题(确信
posted @ 2020-12-10 19:36  面包络合物  阅读(63)  评论(0编辑  收藏  举报