• 【XSY1295】calc n个点n条边无向连通图计数 prufer序列


    题目大意

      求(n)个点(n)条边的无向连通图的个数

      (nleq 5000)

    题解

      显然是一个环上有很多外向树。

      首先有一个东西:(n)个点选(k)个点作为树的根的生成森林个数为:

    [inom{n}{k} imes n^{n-k-1} imes k ]

      前面(inom{n}{k})是这些根的选编号的方案数,后面是prufer序列得到的:前面(n-k-1)个数可以是(1)~(n),第(n-k)个数是(1)~(k)

      我的理解是:每个序列决定了一部分点作为"叶子节点",剩下的每个点按顺序选一个编号最小的"叶子节点"作为这个点的儿子(选编号最小的是因为1.如果一个点可以选多个儿子就不会重复计数;2.两个数的先后顺序不同,那么选的儿子也不同,会让先后顺序成为影响因素),然后如果这个点不能再选儿子,那么这个点就会成为"叶子节点"。选了(n-k-1)个点后会剩下(k)个根和一个不是根的点,然后(k)个根中的一个点连向剩下这个点。

      最后(k)个点的环的排列方式有(frac{(k-1)!}{2})。你可以选编号最小的点为"根",剩下(k-1)个点每次选一个点连向上一个点,最后一个点再连向第一个点。因为环可以翻转,所以方案数要除以(2)。你也可以认为是先生成一个排列,然后旋转这个环(除以(k)),然后翻转这个环(除以(2))。

      最终的式子是

    [egin{align} &~~~~~sum_{k=3}^{n}inom{n}{k} imes n^{n-k-1} imes k imes frac{(k-1)!}{2}\ &=sum_{k=3}^{n}frac{n! imes n^{n-k-1} imes k imes (k-1)!}{k! imes (n-k)! imes 2}\ &=sum_{k=3}^{n}frac{n!n^{n-k-1}}{2(n-k)!} end{align} ]

      写个高精度什么的乱搞一下就可以了。

      时间复杂度:(O(n^2))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    int p=10000;
    struct bign
    {
    	int a[5010];
    	bign()
    	{
    		memset(a,0,sizeof a);
    	}
    	int &operator [](int x)
    	{
    		return a[x];
    	}
    	bign &operator *=(int v)
    	{
    		int i,s,g=0;
    		bign &a=*this;
    		for(i=1;i<=5000;i++)
    		{
    			s=g+a[i]*v;
    			g=s/p;
    			a[i]=s%p;
    		}
    		return a;
    	}
    	bign &operator /=(int v)
    	{
    		int i,s,g=0;
    		bign &a=*this;
    		for(i=5000;i>=1;i--)
    		{
    			s=g*p+a[i];
    			a[i]=s/v;
    			g=s%v;
    		}
    		g=0;
    		for(i=1;i<=5000;i++)
    		{
    			s=g+a[i];
    			a[i]=s%p;
    			g=s/p;
    		}
    		return a;
    	}
    	bign &operator +=(bign &b)
    	{
    		int i,s,g=0;
    		bign &a=*this;
    		for(i=1;i<=5000;i++)
    		{
    			s=a[i]+b[i]+g;
    			a[i]=s%p;
    			g=s/p;
    		}
    		return a;
    	}
    };
    bign a,ans;
    int main()
    {
    	int n;
    	scanf("%d",&n);
    	int i;
    	a[1]=1;
    	for(i=2;i<=n-1;i++)
    		a*=i;
    	ans+=a;
    	for(i=n-1;i>=3;i--)
    	{
    		a*=n;
    		a/=n-i;
    		ans+=a;
    	}
    	ans/=2;
    	for(i=5000;!ans[i];i--);
    	printf("%d",ans[i]);
    	for(i--;i;i--)
    		printf("%04d",ans[i]);
    	printf("
    ");
    	return 0;
    }
    
  • 相关阅读:
    TypeScript(5)类、继承、多态
    TypeScript(6)函数
    iis服务器如何安装ssl证书,Microsoft IIS安装SSL证书
    python3教程:json、pickle和sqlite3持久化存储字典对象
    Python教程:常用网页字符串处理技巧
    global protect 链接已断开或者正在链接仍在工作中的解决记录
    php 上传文件压缩包 running
    phpfpm 重启命令 running
    后台方式运行php 脚本 running
    es常用聚合查询及案例
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8511316.html
Copyright © 2020-2023  润新知