zoukankan      html  css  js  c++  java
  • P4727 [HNOI2009]图的同构记数 题解

    P4727 [HNOI2009]图的同构记数 题解

    题意:求n个点的无标号简单无向图有多少种。n<=60

    首先我们容易知道n个点的有标号无向图个数是(2^{frac{n*(n-1)}{2}})的,但是这些图中有很多是同构的,我们要把这些同构的排除掉。也就是说,所有的标号无向图根据是否同构分成了若干等价类,我们就是要统计其中等价类的个数。而对于两个有标号无向图,它们同构的充要条件是存在一个排列(P_i),使得第一个图中的所有点i换到原来(P_i)的位置上后它与第二个图完全一样。

    那么我们就建立了一个模型,我们手上有一个由所有的有标号无向图组成的集合,我们还有一个置换群,其中包含所有的排列,如果一个集合中的一个元素可以经过置换得到另一个元素,那么这两个元素就在同一个等价类里面,问可以把这个集合分成多少个等价类。

    这个问题很显然可以用Burnside引理解决,具体地,设置换群为(G)(C(P_i))为置换(P_i)下有多少个有标号无向图经过这个置换后还是它本身,那么我们的等价类个数:

    [L=sum_{P_iin G}frac{C(P_i)}{|G|} ]

    我们看要怎么计算不动点个数,首先每个有标号无向图都可以由它的边集({(u,v)})唯一表示,那么一张图经过置换(P_i)后还是它本身等价于({(P_u,P_v)}={(u,v)}) ,也就是(forall (u,v)in E,(P_u,P_v)in E)

    怎么计算满足这样条件的图的个数呢?我们知道,一个置换可以被分解为若干个循环(Burnside常用套路),那么上面的限制条件相当于如果两个点之间有连边,那么它们所在循环的下一个点之间也要有连边,相当于一开始第一个循环的第i个位置和第二个循环的第j个位置有连边,那么接下来令i++,j++,继续在i和j之间连边,如此循环下去,可以发现一共会连出两个环长的lcm条边,那么这些边相当于只有两种选择:要么都不连,要么全都连。并且这样的边一共有gcd(环长组),那么连边的总方案数为(2^{gcd}),将这些环两两之间连边的方案数乘起来,再乘以每个环内部连边的方案数(为(2^{lfloorfrac{s}{2} floor}),其中s为这个环的环长),那么就得到了这个置换下的不动点个数。

    但是我们是不能枚举每个置换来计算的,这样的复杂度是(O(n!))的,但是我们发现一种置换的贡献只与它分解出来的所有环的环长有关,我们可以枚举每个环的环长,然后可以计算将这n个点划分到这几个环中的方案数,然后对于一种划分,我们又可以计算它对应的置换的个数,这样就可以对所有本质相同的置换合并算贡献了。

    具体的,所有置换下不动点个数之和为:

    [sum_{s_1leq s_2...leq s_m,s_1+s_2...+s_m=n}frac{n!}{prod s_i!}frac{1}{prod_{k=1}^{n}(sum_{i=1}^m [s_i=k])!}prod(s_i-1)!*prod 2^{lfloorfrac{s_i}{2} floor}*prod_{i=1}^mprod_{j=i+1}^m2^{gcd(s_i,s_j)} ]

    最后再除以置换群的大小(n!)就是答案。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define N 107
    const int mod=997;
    int inv[N],gd[N][N],po[N];
    int a[N],n,res,c[N];
    int p2(int x){return x*x%mod;}
    int pw(int x,int p)
    {
        return p?p2(pw(x,p/2))*(p&1?x:1)%mod:1;
    }
    int gcd(int x,int y)
    {
        return y?gcd(y,x%y):x;
    }
    void init()
    {
        inv[1]=1;
        for(int i=2;i<=n;i++)
    		inv[i]=mod-mod/i*inv[mod%i]%mod;
        for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    	    	gd[i][j]=gcd(i,j);
        po[0]=1;
        for(int i=1;i<=n;i++)po[i]=po[i-1]*2%mod;
    }
    void dfs(int x,int d,int s,int ans)
    {
        if(s==0)
        {
            res=(res+ans)%mod;
            return ;
        }
        for(int i=min(d,s);i>=1;i--)
        {
            a[x]=i;c[i]++;
            int v=ans;
            v=v*inv[i]%mod*inv[c[i]]%mod*po[i/2]%mod;
            for(int j=1;j<x;j++)v=v*po[gd[i][a[j]]]%mod;
            dfs(x+1,i,s-i,v);
            c[i]--;
        }
    }
    int main()
    {
        scanf("%d",&n);
        init();
        dfs(1,n,n,1);
        printf("%d
    ",res);
        return 0;
    }
    
    

    EX Problem:

    求有多少本质不同的不超过 n 个点的、无重边、可以有自环、存在至少一条欧拉回路的带
    标号无向图。

    首先带标号的点度均为偶数的无向图数量是(2^{C_{n-1}^2}),因为将一个点与剩下的n-2个点连边后,最后一个点的连边情况就确定了,所以每个点对答案的贡献都会除以2(相对不要求点度的无向图来说)

    我们一样像上面一样讨论,只是最后求不动点个数的时候要保证所有点的度数均为偶数,这个连边的时候讨论一下奇偶性就可以了,注意可以连自环。

    然后我们可以得到(f_i)表示i个点的度为偶的无向图个数,我们还要保证连通,设(g_i)为保证连通的图的个数,那么有:

    [g_n=f_n-sum_{s_1leq s_2...leq s_m,s_1+s_2...+s_m=n,mgeq 2}prod_{i=1}^n overline{C}_{g_i}^{d_i} ]

    其中(d_i=sum_{j=1}^{m}[s_j=i])(overline{C}_n^m)为可重组合数。

  • 相关阅读:
    第03组 团队Git现场编程实战
    团队Git现场编程实战
    第二次结对编程作业
    团队项目-需求分析报告
    团队项目-选题报告
    第一次结对编程作业
    第一次个人编程作业
    第一次博客作业
    第四组 团队Git现场编程实战
    第二次结对编程作业
  • 原文地址:https://www.cnblogs.com/lishuyu2003/p/12217835.html
Copyright © 2011-2022 走看看