返回顶部

[计数DP]How Many Of Them

How Many of Them

题目描述

在无向连通图中,若一条边被删除后,图会分成不连通的两部分,则称该边为割边。

求满足如下条件的无向连通图的数量:

  1. n 个结点构成,结点有标号。

  2. 割边不超过 m 条。

  3. 没有重边和自环。

答案对 109+7 取模。

输入格式

仅一行,两个整数 nm

输出格式

一个整数,表示答案。

样例 #1

样例输入 #1

3 3

样例输出 #1

4

样例 #2

样例输入 #2

5 1

样例输出 #2

453

提示

2n50,0mn(n1)2

Source: Gennady Korotkevich (tourist), ITMO University.

做这题前可以做一做连通图Connected Graph
这道题思想很好,运用容斥原理,找到1为基准点,由题目,我们可以想到设Fi,j为有i个点的无向图中有j条割边,
如何转移呢,连通图Connected Graph这道题,我们知道包含1且i个点组成的无向图有hi=2i(i1)2j=1i1hj×Ci1j1×2(ij)(ij1)2,但是本题多加一条限制,最多M条割边
所以需要减去1 i1条割边的情况fi,0=hij=1i1fi,j
那如何先求出fi,j呢,我们假设1这个点所在的连通块包含的点有k个,则有fk,0×Ci1k1种情况,设gi,j,xij,x,则除去1所在的连通块,还有x=1min(ik,j)gik,jx,x种情况,因为1这个点所在的连通块包含的k个点都有可能与x个连通块相连,所以再乘上kx
即为fi,j=k=1i1fk,0×Ci1k1×x=1min(ik,j)gik,jx,x
好现在就剩下g如何求了
按照上面的思路,我们可以求出gi,j,k=p=1i1q=0jfp,q×Cp1q1×gip,jq,k1×p每个连通块多乘了一个p,因为p个点都可能与g所构成的连通块相连

点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int mod=1e9+7;
int n,m;ll f[55][1505],C[1500][1500],h[55],g[55][55][55];
ll qpow(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1)ans=ans*a%mod;
		b>>=1;
		a=a*a%mod;
	}
	return ans;
}
int main()
{
	speed();
	cin>>n>>m;
	for(int i=0;i<=50;i++)
	{
		C[i][i]=1;C[i][0]=1;
		for(int j=1;j<=i;j++)
		{
			C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
		}	
	}
	h[1]=1;
	for(int i=2;i<=n;i++)
	{
		h[i]=qpow(2,i*(i-1)/2);
		for(int j=1;j<=i-1;j++)
		{
			h[i]-=h[j]*C[i-1][j-1]%mod*qpow(2,(i-j)*(i-j-1)/2)%mod;
			h[i]=(h[i]%mod+mod)%mod;
		}
	}
	g[0][0][0]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i-1;j++)
		{
			for(int k=1;k<=i-1;k++)
			{
				for(int x=1;x<=min(i-k,j);x++)
				{
					f[i][j]=(f[i][j]+f[k][0]*C[i-1][k-1]%mod*g[i-k][j-x][x]%mod*qpow(k,x))%mod;
				}
			}
		}
		f[i][0]=h[i];
		for(int j=1;j<=i-1;j++)
		{
			f[i][0]-=f[i][j];
			f[i][0]=(f[i][0]%mod+mod)%mod;
		}
		for(int j=0;j<i;j++)//atention
		{
			for(int k=1;k<=i;k++)
//			{
				for(int p=1;p<=i;p++)
				{
					for(int q=0;q<=j;q++)
					{
						g[i][j][k]=(g[i][j][k]+f[p][q]*C[i-1][p-1]%mod*g[i-p][j-q][k-1]%mod*p)%mod;
					}
				}
//			}
		}
	}
	ll ans=0;
	for(int i=0;i<=min(n,m);i++)
	{
		ans=(ans+f[n][i])%mod;
	}
	cout<<ans;
	return 0;
}
posted @   wlesq  阅读(48)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探
点击右上角即可分享
微信分享提示