首页 > 代码库 > 【群论】polya定理

【群论】polya定理

对Polya定理的个人认识

    我们先来看一道经典题目:

    He‘s Circles(SGU 294)

        有一个长度为N的环,上面写着“X”和“E”,问本质不同的环有多少个(不能旋转重复就称之为本质不同)

    输入样例:4

    输出样例:6

 

    那么要怎么办呢?暴力显然暴不出来……

    我们可以考虑使用置换群。

    我们有两种算法:

        ①Burnside引理:

             答案直接为1/|G|*(D(a1)+D(a2)+D(a3)+……+D(as))

             其中D(ak)为在进行置换群置换操作ak下不变的元素的个数。

             在N=4下一共有四个置换群:

             (1 2 3 4    (1 2 3 4    (1 2 3 4    (1 2 3 4

              1 2 3 4)    2 3 4 1)    3 4 1 2)    4 1 2 3)

             那么显然在置换a1下都不变,那么D(a1)=16 (4*4)

             EEEE和XXXX在置换a2下都不变,所以D(a2)=2

             XXXX和EEEE还有XEXE以及EXEX在置换a3下都不变,所以D(a3)=4

             XXXX和EEEE在置换a4的情况下都不变,D(a4)=2

             

             最后根据公式计算出1/|4|*(16+2+4+2)=6(种)

 

        ②Polya定理

             回顾上面的Burnside算法,是否感觉D不太好实现呢?

             那么我们就可以用一种更容易理解、适应力强、时间复杂度低、编程复杂度低的方法就是群论的最厉害的Polya定理

             其实Polya定理与Burnside引理本质上的区别并不是很大,只不过入手问题的角度不一样。

             我们可以发现,一个循环节之间的“不变元素”可以互相交换从而不影响整体,所以我们可以设Ci为置换群i的循环节个数。

             例如(1 2 3 4 5

                   3 5 1 4 2)

             的循环节就为:1和3循环1->3->1……

                                 2和5循环2->5->2……

                                 4和它自身循环4->4->4……

           那么循环节数就为3

           再回来看现在这个题目,我们可以抽象地把Ci替换掉Di

           那么Di=p^C(i) (p为总共的字母数)

           相同循环节中的元素可以互相置换,所以Di=p^C(i)

           polya公式为1/|G|(p^C(1)+p^C(2)+……+p^C(s))

           以4为例,则1/|G|=1/4

          C(1):循环节为(1)(2)(3)(4),所以C(1)=4

          C(2):循环节为(4 3 2 1),所以C(2)=1

          C(3):循环节为(1 3)(2 4),所以C(3)=2

          C(4):循环节为(1 2 3 4),所以C(4)=1

          那么答案就为1/4(2^4+2^1+2^2+2^1)=6

          这里的C相对于上面的D来说要简单,记得XJR学长给我讲过环的判定,直接任选一个没有选过的点,从这个点开始映射,走过的点标上1,等到再走到标上1时,结束,统计数加1

          

void search(int M){	int i=M;//一开始从这里开始	while(!flag[b[i]]){//如果它的映射没被访问过,那么说明它还没有构成环		i=b[i];//继续映射		flag[i]=1;//标记已访问	}	return ;//返回}int C(){	int tmp=0;	for(int i=1;i<=N;i++) if(!flag[i]) flag[i]=1,search(i),tmp++;//环数加1	return tmp;//返回循环节数}

  那么我们再加上一个快速幂,就可以进一步优化。

【群论】polya定理