polya定理 和 置换 poj2409

47 篇文章 0 订阅

 

所属题型:组合数学

要求知识:polya或者burnside

题意转述:一串由n个珠子组成的项链,用c种颜色涂染,问能形成多少种不同项链。

限制:旋转得来的为同一种,翻转得来的也为同一种。

本题有多种算法,下面给出比较容易想到且易于理解的两种算法。

推荐使用算法2,因为若是碰到高精度问题,算法2比算法1易于处理,且复杂度也比算法1低好多。核心知识点都是Polya定理。

解决过程:

算法一:

I.计算旋转置换和翻转置换的个数:

1.旋转置换

   N个珠子,把项链当成一个圆,每次旋转角度为I*360/N(I∈(1,n)),共有N次不同旋转。

2.翻转置换

⊙考虑对称轴:

n为奇数. 只有一种对称轴, 即轴穿过一个点. 这样有N种置换。

n为偶数, 有两种翻转:

轴每边n/2个点. 这样的置换有n/2个;

轴穿两点, 每边n/2个点. 这样的置换也有n/2个;

这样算出来结果还是有n个置换,即n为奇偶数是置换个数是一样的。

综上所述,共有2*N次不同置换,即有|G|=2N。

II.每个置换的循环节数

1.旋转置换

第i次旋转对应的置换结果:

for(j=0; j<n; j++) { g[j]=(i+j)%n; } 循环节数count由一下循环求出: for(j=0, count=0; j<n; j++) { //求每个旋转置换的循环节数,和寻找连通子图类似. if(flag[j]==0) { //若j结点未曾访问过,表示一个新的循环,count++. count++; for(k=j; flag[k]==0; k=g[k]) flag[k]=1; } } 

2.翻转置换

    第i次翻转对应的置换结果:

for(j=1; (j+j)<n; j++) { //每次翻转置换的结果,沿翻转轴对称点交换位置. //由于程序里每次旋转置换在翻转置换之前进行,故每次只要用 //同一个翻转循环处理,而不必分情况讨论. k=g[j]; g[j]=g[n-j]; g[n-j]=k; } 循环节数count由以下循环求出: for(j=0, count=0; j<n; j++) { //求每个翻转置换的循环节数,和寻找连通子图类似. if(flag[j]==0) { //若j结点未曾访问过,表示一个新的循环,count++. count++; for(k=j; flag[k]==0; k=g[k]) flag[k]=1; } } 

 

算法二:

本题还可以快速算出每个置换的循环(或者轮换)个数,达到快速求解的目的:

分析(1)

1.旋转.

考虑顺时针旋转i格的置换:

循环个数为gcd(n,i)

每个循环的长度为L=n/gcd(n,i)

2.翻转

考虑对称轴

***n为奇数. 只有一种对称轴, 即轴穿过一个点. 有[n/2]个循环长度为2, 还有一个循环长度为1(被穿过的点), V=C([n/2], [m/2]).

***n为偶数, 有两种翻转

轴每边n/2个点. 这样的置换有n/2个

轴穿两点, 每边n/2个点. 这样的置换也有n/2个

算法复杂度分析:很容易可以算出这个算法的时间复杂度为O(n)。

分析(2):

 

Polya定理:设G是n个对象的一个置换群,用m种颜色涂染这n个对象,则不同染色的方案数L=1/|G|*[m^p(a1)+m^p(a2)+....+m^p(an)].其中p(ai)是某个置换的循环数.

1.旋转置换.

我们假设依次顺时针旋转1~n个,则循环个数=gcd(i,n);

2.翻转置换

当n为偶数时,分两种情况,一种是中心轴在两个对称对象上,则循环个数为n/2+1,另一种是对称轴两边分别有n/2个对象,则循环个数为n/2;

当n为奇数时,对称轴就只能在一个对象上,则循环个数为n/2+1;

 

void polya(int p, int n) { int i; ans = 0; for(i=0; i<n; i++) //第i次旋转的循环节数为gcd(n,i); ans += pow(p*1.0, gcd(n, i)); if(n % 2) //n为奇数 { for(i=0; i<n; i++) //共有n个循环节数均为 n/2+1 的置换; ans += pow(p*1.0, n/2+1); } else //n为偶数 { for(i=0; i<n/2; i++) //如上面所述有两种置换,第一种循环节数均为n/2, ans += pow(p*1.0, n/2) + pow(p*1.0, n/2+1); //第二种循环节数均为n/2+1; } } 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值