BZOJ 3925 地震后的幻想乡

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

题目
我们可以换个方向统计:枚举前k小的边,如果这些边使图联通并且减去第k小的边会使图不连通,那么就可以产生贡献。
那么:
a n s = k = 1 m E ( k ) k m + 1 ans = \sum_{k=1}^{m} E(k)\frac k{m+1}
其中 E ( k ) E(k) 为前k条边使图联通且前k-1条边使图不连通。
a n s = k = 1 m E ( k ) i = 1 k 1 m + 1 ans = \frac {\sum_{k=1}^{m} E(k) * \sum_{i=1}^k1}{m+1}
a n s = k = 1 m i = k m E ( i ) m + 1 ans = \frac{\sum_{k=1}^{m} \sum_{i=k}^m E(i) }{m+1}
i = k m E ( i ) \sum_{i=k}^mE(i) 的值就等于 E [ k 1 使 ] E[前k-1条边不能使图联通]
这个就可以补集转化状压DP了。

AC Code:

#include<bits/stdc++.h>
#define maxn 11
#define maxm 55
using namespace std;

int n,m;
int sz[1<<maxn],lg[1<<maxn];
double C[maxm][maxm],f[maxm][1<<maxn][2];
int c[maxn][maxn];

int main()
{
	scanf("%d%d",&n,&m);
	C[0][0] = 1;
	for(int i=1;i<maxm;i++)
	{
		C[i][0] = 1;
		for(int j=1;j<=i;j++)
			C[i][j] = C[i-1][j-1] + C[i-1][j];
	}
	for(int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),u--,v--,c[u][v]=c[v][u]=1;
	for(int i=0;i<n;i++) lg[1<<i] = i;
	for(int i=1;i<(1<<n);i++)
	{
		int tmp = i & (-i) , v = lg[i & (-i)],rsta=i-tmp;
		sz[i] = sz[rsta];
		for(int j=0;j<n;j++)
			if((rsta)>>j&1)
				sz[i] += c[j][v];
	}
	for(int sta=1;sta<(1<<n);sta++)
	{
		for(int i=0;i<=sz[sta];i++)
		{
			int p = sta & (-sta);
			for(int t=sta;t;t=(t-1)&(sta))
				if((t&p) && (t!=sta))
				{
					for(int k=0;k<=i;k++)
						f[i][sta][0] += f[k][t][1] * C[sz[sta-t]][i-k];
				}
			f[i][sta][1] = C[sz[sta]][i] - f[i][sta][0];
		}
	}
	
	double ans = 0;
	for(int i=0;i<=m;i++) 
		ans += f[i][(1<<n)-1][0] / C[m][i];
	ans /= m+1;
	printf("%.6lf\n",ans);
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/87392018