初学polya

一篇比较好的论文:http://wenku.baidu.com/link?url=KSN5ZBbKMsHr17dRdMIXnXQHi0HLMM8cRhC2d32zFmHFk3LF288Y9h50yIQCBNnkgeAPFM0iC1Y8HT-TyLK-wTaQq-eW5WV3UU4tHKBjLAW
基本定理 :
    1,burnside引理: Ans=(D(1)+D(2)+...D(G))/G  D(i)表示在置换i下本质不同的状态数,G表示置换集合.
    例题:bzoj1004 cards (虽然这道题可以其他方法水过,因为有‘任意多次洗牌都可用这 m种洗牌法中的一种代替’这一条件).
    2,polya定理: Ans=(k^v(1)+k^v(2)+k^v(3)+....k^v(G))/G v(i)表示在置换i下的循环个数.
循环的定义: 
    设有置换群 a[1],a[2],a[3].....a[n].
               b[1],b[2],b[3].....b[n].
    若有b[1]=a[2],b[2]=a[3]....b[n-1]=a[n],b[n]=a[1]则称为1个n阶循环.
例题:bzoj1488 图的同构.


这里说一下bzoj1488的做法:
    Ans=(2^v(1)+2^v(2)+....2^v(G))/(G) (v(i)为在i置换下边循环的个数,k=2因为边只有选与不选两种情况.)
    首先有:点置换一一对应边置换,这一性质,因此G=n!(即点置换数),因为G太大了,无法一一求出v(i),我们考虑优化方法.
    我们知道,如果点置换划分出的循环相同,那么由这样一类的点置换引起的边置换是类似的。
    所以我们不妨先枚举点置换的循坏,即枚举大小为i的点循环的个数,设其为num[i].
    然后所有的边就被划分成了2类,在一个点循坏内的边,和在两个点循环之间的边,我们现在要统计边循坏的个数.
    对于在一个点循坏内的边 :我们设循环大小为n.
        那么边就分成这么几种:相邻两个点连的边,隔一个点连的边,隔两个....但是当隔x个连一条边并且x>n/2时,我们发现此时和隔n-x连一条边是等价的.
因此边循坏的个数就是n/2了.
    对于在两个点循环内的边 :我们设循环大小分别为n,m
        那么假设对于任意一条边 <a[i],b[j]>我们枚举它的下一条边<a[i]+1,b[j]+1>,<a[i]+2,b[j]+2>...直到重新枚举到<a[i],b[j]>显然已经枚举了lcm(m,n)条边。
一共有m*n条边,所以一共的循环个数就是(m*n)/(lcm(n,m))=gcd(m,n).
    所以统计循环就到这里了,但是别忘了我们枚举的是一类点循环而不是一种,我们需要计算这种点循环有多少个....
(以下用c[i][j]表示i个数选j个数的组合)
tot=c[n][size[1]]*c[n-size[1]][size[2]]*c[n-size[1]-size[2]][size[3]].......c[size[m]][size[m]] (size[x]为第x个点循环的大小)
然而因为可能出现size[i]=size[j]的情况,我们之上的式子是把它们当成了两块算的,但是实际无论它们的先后如何,本质都是一样的。

所以tot*=num[1]!*num[2]!*....num[n]!来消除位置的影响 (num[x]为大小为x的点循环的个数)

然后对于每个点循环,我们需要从当前k个点中选n个点构成循环,那么tot再乘上每一个(n[i]-1)!

    所以这一种情况的答案就是 边循环数*tot .累加所有情况的答案就可以了.
(中间过程中的许多地方需要用到ksm,费马小定理求逆元等,注意).


毕姥爷的拓展:将原图的无向图改成有向图 ::
    唯一的变化就是统计边循坏的时候,首先如果是点循环之间的边循环直接乘以2就可以了。
    点循环的内部的边循坏则需要分类讨论:
若n%2==0 边循环数为 (n/2)*2-1 (注意不是n-1,下同)
否则为 (n/2)*2 
    
    
    

你可能感兴趣的:(Polya,bzoj1488)