Polya定理:
设G是一个p个对象的置换群,那么用k种颜色对p个对象进行染色!当一种方案在群G的作用下变为另外一种方案,那么我们这个时候就认为这两个方案是一样的。那么在这种规定下不同的染色方案为:
n=(Ek^m(f))/|G|,其中m(f)是置换f的循环节。
Polya定理是基于Burnside定理和另外一个定理的,其中Burnside定理的通俗表达方法如下:
1)如果令C(f)表示在置换f的作用下,本质不变的着色方案数!那么可以证明的是“本质不同的着色方案数就是所有置换f下的C(f)的平均数”。
在Burnside的基础上,我们在介绍一个定理:
2)如果使用k种颜色给有限集合S着色,那么对于一个置换f,在该置换下本质不变的着色方案数就是C(f)=k^(m(f)),其中m(f)是置换f的循环节数。
基于上面的1)2)两个定理,便很明显的得到Polya定理。
介绍了Polya定理之后,我们来看看Polya的简单应用,在POJ 1286题中,如果是旋转或者是对称变换相同的着色方案算作一种着色方案数。那么我们直接使用Polya定理进行求解就行了,但是这个时候对奇数和偶数的情况下对称变换的置换是不一样的,分开求解就可以了!对于旋转的置换的循环节我们直接进行dfs求解就可以了。
#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> using namespace std; typedef long long LL; LL myPow(LL a,int b) { LL sum=1LL; while(b) { if(b%2==1) { sum*=a; } a*=a; b/=2; } return sum; } int vis[30],adj[30]; void dfs(int i) { if(vis[i]==0) { vis[i]=1; dfs(adj[i]); } } int find(int s,int n) { memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) { int e=(s+i-1)%n; if(e==0) e=n; adj[i]=e; } int sum=0; for(int i=1;i<=n;i++) { if(vis[i]==0) { dfs(i); sum++; } } return sum; } int main() { int n; LL a,b; while(scanf("%d",&n)) { if(n==-1) break; if(n<=0) { printf("0\n"); continue; } if(n%2==0) { a=myPow(3LL,n); for(int i=2;i<=n;i++) { int tn=find(i,n); a+=myPow(3LL,tn); } b=(LL)n; a=a+(LL)(n/2)*(myPow(3LL,(n+2)/2)); a=a+(LL)(n/2)*(myPow(3LL,n/2)); b+=(LL)n; } else { a=myPow(3LL,n); for(int i=2;i<=n;i++) { int tn=find(i,n); a+=myPow(3LL,tn); } b=(LL)n; a=a+(LL)n*(myPow(3LL,1+(n-1)/2)); b+=(LL)n; } printf("%lld\n",a/b); } return 0; }