UVA821

题目的大意是求所有点对之间最短路之和的平均值。要求所有点对之间的最短路(即全源最短路),并且数据范围很小。很容易想到使用 Floyd 算法。

Floyd 的实现(会用的可以跳过)

Floyd 本质上是一种动态规划。设 \(d_{i,j}\) 表示从 \(i\)\(j\) 的最短路径的长度(注意题目输入为有向边,所以 \(d_{i,j}\)\(d_{j,i}\) 的意义不一样),\(n\) 为最大点的编号。

初始时,若 \(i\)\(j\) 之间存在有向边,那么 \(d_{i,j}=1\)(表示可以直接从 \(i\) 跳到 \(j\)),否则给 \(d_{i,j}\) 赋予一个大数即可(表示 \(i\)\(j\) 之间没有直接连接,注意不要太大了,避免超出范围)。

考虑在求 \(i\)\(j\) 的最短路时,枚举一个中转点 \(k\),并且计算从 \(i\)\(k\),从 \(k\)\(j\) 的最短路径之和,并用此更新 \(d_{i,j}\),可以得到如下转移方程:

\[d_{i,j}=\min(d_{i,j},d_{i,k}+d_{k,j}) \]

注意在实现 Floyd 时,应当先枚举 \(k\)(即中转点),再枚举 \(i\)\(j\)(起点和终点),这样做可以保证 \(d_{i,k}\)\(d_{k,j}\) 都被计算过,从而更新答案。

最后在统计时,只需求出所有点对之间的最短路之和,再除以计算过的点的次数之和,保留三位小数。

具体实现如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int d[101][101],n,ans,t,T;
int main()
{
	while(true)
	{
		T++;
		for(int i=1;i<=100;i++)
			for(int j=1;j<=100;j++)
				d[i][j]=0x3f3f3f3f;
		int a,b;
		n=0;
		ans=0;
		t=0;
		while(true)
		{
			cin>>a>>b;
			if(a==0&&b==0)
			{
				if(n==0) return 0;
				else break;
			}
			d[a][b]=1;
			n=max(n,max(a,b));
		}
		for(int k=1;k<=n;k++)
			for(int i=1;i<=n;i++)
				for(int j=1;j<=n;j++)
					d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				if(i!=j&&d[i][j]<0x3f3f3f3f)	
				{
					t+=d[i][j];
					ans++;
				}
		printf("Case %d: average length between pages = %.3f clicks\n",T,(t*1.0)/(ans*1.0));
	}
	return 0;
}
posted @ 2024-01-20 17:32  liyilang2021  阅读(3)  评论(0编辑  收藏  举报