hihoCoder 1047 Random Tree

一道网上没有解题的题目,所以写一写留个纪念.

贴题

#1047 : Random Tree
时间限制:20000ms
单点时限:2000ms
内存限制:256MB
描述
给一无向带权完全图。我们等概率随机一棵生成树。求每两点间路径长度的期望。


输入
第一行一个整数n。 下面n行每行n个整数。第i行第j个整数ai, j为i到j的边的长度。


数据保证ai, i = 0且对于所有i, j有ai, j = aj, i。


2 ≤ n ≤ 1000


 - 1000 ≤ ai, j ≤ 1000


输出
输出n行。每行包含n个实数。第i行第j个整数为i到j的路径的期望长度。


输出与标准答案相对误差或绝对误差不超过1e-9则视为正确。

完全图等概生成一颗生成树,求树上两点距离的期望矩阵.感觉有一定实际意义,可以用来衡量特定网络环境中两点距离

固定两点A,B

1.两个端点是A或B,这类边被取到的概率sigma(d)/(n-1)/n = 2/n

2.一个端点是A或B,1/n

3,没有端点是A或B,则A,B路径距离至少是3,考虑A,B路径长为k的中包含该类边e,假设e的两个端点为C,D

完全图中有n^(n-2)颗生成树,根据prufer编码可得

而A,B路径为k的路径的prufer编码有 A(n-4,k-3)*(k-2)*n^(n-k-2) * (k+1)种,

(除A,B,C,D外,A,B k路径中有k-3个点,排列A(n-4,k-3)*(k-2)对应不同A,B路径,给A,B标号最大,根据prufer编码,该树前(n-k-2)有n种编号,第n-k-1有k+1种编号,后面的固定)

比一下就可以得到概率,k从3循环到n-1求和可得到正确的答案. 

#include <cstdio>
#pragma warning(disable:4996)
using namespace std;
const int bign = 1033;
double sum[2][bign][bign];
double a[bign][bign];
int n;
double ans[bign][bign];
long double A[bign];
double P[bign];
long double total = 0;
long double mypower(long double a, int b)
{
	long double res = 1;
	while (b)
	{
		if (b & 1)
			res *= a;
		a = a*a;
		b >>= 1;
	}
	return res;
}
void init()
{
	A[0] = 1;
	A[1] = ((long double)n - 4)/n;
	for (int k = 2; k <= n - 4; k++)
	{
		A[k] = A[k - 1] * (n - k - 3)/n;
	}

}
int main()
{
	scanf("%d", &n);
	init();
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
		{
			scanf("%lf", &a[i][j]);
			sum[0][i][j] = sum[0][i][j - 1] + a[i][j];
			sum[1][i][j] = sum[1][i - 1][j] + a[i][j];
			total += a[i][j];
		}

	long double para = 0;
	for (int k = 3; k <= n - 1; k++)
	{
		para += A[k - 3] * (k + 1) / n * (k - 2) / n / n ;
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			long double tmp = (sum[0][i][n] + sum[1][n][j]) / n;
			tmp += (total - 2 * (sum[0][i][n] + sum[1][n][j]) + 2 * a[i][j]) * para;
			if (i == j)
				tmp = 0;
			printf("%.12Lf", tmp);
			printf("%c", (j == n) ? '\n' : ' ');
		}
	}
}

/*
5
0 1 1 1 1
1 0 1 1 1
1 1 0 1 1
1 1 1 0 1
1 1 1 1 0
4
0 1 1 1
1 0 1 1
1 1 0 1
1 1 1 0
6
0 1 1 1 1 1
1 0 1 1 1 1
1 1 0 1 1 1
1 1 1 0 1 1
1 1 1 1 0 1
1 1 1 1 1 0
*/




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值