BZOJ 3534 重建

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/88189280

a n s = S ( ( i , j ) S P [ i ] [ j ] ( i , j ) S ( 1 P [ i ] [ j ] ) ) = ( i , j ) G ( 1 P [ i ] [ j ] ) S ( ( i , j ) S P [ i ] [ j ] 1 P [ i ] [ j ] ) \begin{aligned} ans &= \sum_{S}\left(\prod_{(i,j) \in S}P[i][j] \prod_{(i,j) \notin S} (1-P[i][j]) \right)\\ &=\prod_{(i,j)\in G}(1-P[i][j]) \sum_{S}\left(\prod_{(i,j)\in S} \frac {P[i][j]}{1-P[i][j]}\right) \end{aligned}

设(i,j)的边权为 P [ i ] [ j ] 1 P [ i ] [ j ] \frac {P[i][j]}{1-P[i][j]} 然后使用矩阵树定理计算积和即可。
PS: P [ i ] [ j ] = 1 P[i][j] = 1 的情况可以把 P [ i ] [ j ] P[i][j] 设为 1 e p s 1-eps ,实际上 1 P [ i ] [ j ] 1-P[i][j] 就变成了eps, 1 1 P [ i ] [ j ] \frac{1}{1-P[i][j]} 就变成了极大值,因为有效位数只有一位,double是可以存1e±328的,如果概率为1的边成了环,也就没有生成树可以包括同样多的 1 1 P [ i ] [ j ] \frac 1{1-P[i][j]} 来抵消掉极小值,舍入后也就是正确答案0。

AC Code:

#include<bits/stdc++.h>
#define maxn 55
#define eps 1e-8
using namespace std;

double P[maxn][maxn],a[maxn][maxn],sumP=1;
int n;

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
		{
			cin>>P[i][j];
			P[i][j] = min(P[i][j] , 1.0-eps);
			if(i!=j)
			{
				a[i][j] = -P[i][j] / (1-P[i][j]);
				if(i<j)
					sumP = sumP * (1-P[i][j]);
				a[i][i] -= a[i][j];
			}
		}
	
	double ans = sumP;
	for(int i=2;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			if(a[j][i])
			{
				if(!a[i][i])
				{
					for(int k=i;k<=n;k++) swap(a[i][k],a[j][k]);
					ans = -ans;
				}
				else
				{
					double tmp = a[j][i] / a[i][i];
					for(int k=i;k<=n;k++)
						a[j][k] -= a[i][k] * tmp;
				}
			}
	for(int i=2;i<=n;i++)
		ans = ans * a[i][i];
		
	cout<<ans;
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/88189280
今日推荐