快樂地打牢基礎(12)——Burnside引理 和 Polya計數公式

前置知識


1.羣的定義

給定一個集合G={a,,b,c,...}G = \{a,,b,c,...\} 和 集合GG上的二元運算"""*",並滿足以下四個條件:

  1. 封閉性:a,bG,cG,ab=c\forall a,b\in G,\exists c \in G,a*b=c
  2. 結合律:a,b,cG,(ab)c=a(bc)\forall a,b,c\in G,(a*b)*c=a*(b*c)
  3. 單位元: eG,aGae=ea=a\exists \ e\in G,\forall a \in G a*e=e* a = a
  4. 逆元:aG,bG,ab=ba=e, b=a1\forall a\in G,\exists b \in G,a*b=b*a=e,記\ b=a^{-1}

則稱GG在運算“*”下十一個羣,簡稱GG是一個羣,一般aba*b簡寫爲abab.。“*”可以是任何運算,如果“*”+“+”,就稱爲加法羣,是ד\times”,就稱爲乘法羣。如果羣GG中的元素是有限的,就稱爲有限羣,否則稱爲無限羣,有限羣中的元素個數稱爲有限羣的階。

2.羣的運算

對於gGg\in G,對於GG的子集HH,定義gH={ghgH}g*H=\{gh|g\in H\},簡寫爲gH;Hg={hghH}gH;H*g=\{hg|h \in H\},簡寫爲HgHg

對於GG的子集A,BA,B,定義AB={abaA,bB}A*B=\{ab|a\in A,b\in B\},簡寫爲ABAB
對於GG的子集HH,記H1={h1hH}H^{-1}=\{h^{-1}|h\in H\}
定理1:若(G,)(G,*)是羣,則對於任一gG,gG=Gg=Gg\in G,gG= Gg=G
定理2:若(G,)(G,*)是羣,HHGG的非空子集,並且(H,)(H,*)也是羣,那麼稱HHGG的子羣。

根據 定理2 可以判斷子集是否爲一個子羣:HH=H,H1=HHH=H,且H^{-1}=H等價於HHGG的子羣。

3.置換

nn個元素1,2,...n1,2,...n之間的一個置換
(12...na1a2...an) \left( \begin{matrix} 1 & 2 & ...&n \\ a_1 & a_2 &...& a_n \end{matrix} \right)
表示 1111nn中的某個數a1a_1取代,2211nn中的某個數a2a_2取代,…,直到nn11nn中的某個數ana_n取代,且a1,a2,...,ana_1,a_2,...,a_n互不相同。

4.置換羣

置換羣的元素是置換,運算是置換的連接。例如:
(12343124)(12344321)=(12343124)(31242431)=(12342431) \left( \begin{matrix} 1 & 2 & 3 & 4 \\ 3 & 1 & 2 & 4 \end{matrix} \right) \left( \begin{matrix} 1 & 2 & 3 & 4 \\ 4 & 3 & 2 & 1 \end{matrix} \right)= \left( \begin{matrix} 1 & 2 & 3 & 4 \\ 3 & 1 & 2 & 4 \end{matrix} \right) \left( \begin{matrix} 3 & 1 & 2 & 4 \\ 2 & 4 & 3 & 1 \end{matrix} \right)= \left( \begin{matrix} 1 & 2 & 3 & 4 \\ 2 & 4 & 3 & 1 \end{matrix} \right)
可以驗證置換羣滿足羣的 4 個條件。

下面舉個題目的例子:

He‘s Circles(SGU294)

題意: 有一個長度爲N的環,上面寫着’X’和’E’,問本質不同的環有多少種。(N不超過200000)。
在這裏插入圖片描述
SGU已經掛掉了,所以不再用這題作爲例題。

主要是用來練習找一下本題中的置換羣G=G ={轉0格,轉1格,轉2格,…,轉n-1格}
轉 0 格:
(12...n12...n) \left( \begin{matrix} 1 & 2 & ...& n \\ 1 & 2 & ... & n \end{matrix} \right)
轉 1 格:
(12...n23...1) \left( \begin{matrix} 1 & 2 & ...& n \\ 2 & 3 & ... & 1 \end{matrix} \right)
轉 2 格:
(12...n34...2) \left( \begin{matrix} 1 & 2 & ...& n \\ 3 & 4 & ... & 2 \end{matrix} \right)
........
轉 n-1 格:
(12...nn1...n1) \left( \begin{matrix} 1 & 2 & ...& n \\ n & 1 & ... & n-1 \end{matrix} \right)

5.循環

先介紹一個循環的概念:
(a1a2...an)=(a1a2...ana2a3ana1) \left( \begin{matrix} a_1 & a_2 & ... & a_n \\ \end{matrix} \right)= \left( \begin{matrix} a_1 & a_2 &... & a_n \\ a_2 & a_3 & a_n & a_1 \end{matrix} \right)
稱爲 nn 階循環。每個置換都可以寫若干互不相交的循環的乘積,兩個循環(a1a2...an)(a_1a_2...a_n)(b1b2...bn)(b_1b_2...b_n) 互不相交是指aibj,i,j=1,2,...,na_i \not =b_j,i,j=1,2,...,n。例如:
(1234535142)=(13)(25)(4) \left( \begin{matrix} 1 & 2 &3 & 4&5 \\ 3 & 5 & 1 & 4&2 \end{matrix} \right)= (13)(25)(4)
置換的循環節數是上述表示中循環的個數。例如(13)(25)(4)(13)(25)(4)的循環節數爲 3。

BurnSide 引理


BurnSide 引理是羣論中的一個重要結論,在組合數學中可用於計算等價類的個數,常用於Polya計數。

1.主要內容:

D(aj)D(a_j) 表示在置換aja_j 下不變的元素的個數(不動點數)。LL表示本質不同的方案數(等價類的個數),G|G| 是置換羣中置換的個數 。
L=1Gj=1D(aj)\displaystyle L = \frac{1}{|G|}\sum_{j = 1}D(a_j)

對於上述 He‘s Circles(SGU294) 例子中N=4N = 4的情況,一共有4個置換:
(12341234)(12342341)(12343412)(12344123) \left( \begin{matrix} 1 & 2 & 3 & 4 \\ 1 & 2 & 3 & 4 \end{matrix} \right) \left( \begin{matrix} 1 & 2 & 3 & 4 \\ 2 & 3 & 4 & 1 \end{matrix} \right) \left( \begin{matrix} 1 & 2 & 3 & 4 \\ 3 & 4 & 1 & 2 \end{matrix} \right) \left( \begin{matrix} 1 & 2 & 3 & 4 \\ 4 & 1 & 2 & 3 \end{matrix} \right)
因爲每個點只有兩個狀態"X"和"E",所以一共有24=162^4=16種情況。

  1. 所有方案在置換a1a_1下都不變,D(a1)=16D(a_1) = 16
  2. XXXX 和 EEEE 在置換a2a_2下不變,D(a2)=2D(a_2) = 2
  3. XXXX 和 EEEE 及 XEXE 和 EXEX 在置換a3a_3下不變,D(a3)=4D(a_3) = 4
  4. XXXX 和 EEEE 在置換a4a_4下不變,D(a4)=2D(a_4) = 2

綜上,L=14(16+2+4+2)6L = \frac{1}{4}(16 + 2 + 4 + 2)=6

下面主要介紹一個經典的案例:方陣着色問題
對於222*2的方陣用黑白兩種顏色塗色,問能得到多少種不同的圖像?經過旋轉使之吻合的兩種方案,算是同一種方案。(圖片來自百度百科)
在這裏插入圖片描述
從圖中我們可以發現 案例3,案例4,案例5,案例6 可以通過旋轉變爲一種,我們就可以把(3,4,5,6)稱爲等價類(具體概念之後會有)。
那麼一共有多少等價類呢?

  • 1
  • 2
  • 3,4,5,6
  • 7,8,9,10
  • 11,12
  • 13,14,15,16

所以我們可以知道等價類數目就是6,仔細想一想,我們可以發現這個例子就和我們上面 SGU例子中,N = 4 是一樣的。

對於四個置換{逆時針旋轉0°,逆時針旋轉90°,逆時針旋轉180°,逆時針旋轉270°},其不動點數分別爲16, 2, 4, 2。所以等價類數目爲(16+2+4+2)/4 = 6。

2.補充的兩個概念

EkE_k等價類: 設kk1,2,...,n1,2,...,n中的某個元素,kk在置換羣GG作用下的軌跡上所有元素的集合

舉個例子:

在方陣着色問題中,

  • 方案 1 在{逆時針旋轉0°,逆時針旋轉90°,逆時針旋轉180°,逆時針旋轉270°}的四個置換下的都是方案1,所以E1={1}E_1=\{1\}
  • 方案 3 ,在{逆時針旋轉0°,逆時針旋轉90°,逆時針旋轉180°,逆時針旋轉270°}的四個置換下分別是方案3,4,5,6所以E3={3,4,5,6}E_3=\{3,4,5,6\}
Zk,kZ_k,k不動置換類:** 設kk1,2,...,n1,2,...,n中的某個元素,在置換羣GG作用下使 kk 的位置保持不變的置換的全體。

舉個例子:

  • 對於上圖的方案 11,{逆時針旋轉0°,逆時針旋轉90°,逆時針旋轉180°,逆時針旋轉270°}的四個置換下分別變成了 方案11 ,方案12,方案11,方案12。所以只有第一個置換和第三個置換保證了位置不變
    Z11={a1,a3}Z_{11}=\{a_1,a_3\}

公式

總結一下:
BurnSide引理就是非等價着色數等於置換羣中保持不變的着色的平均數,

等價類 = 各個置換下不動點個數的和 / 置換羣中的置換個數。

Polya定理


Polay定理實際上是BurnSide引理的具體化,因爲BurnSide中 D(aj)D(a_j) 並不是很好計算,搜索的話要大量的時間,所以Polya 定理提供了計算不動點的具體方法,達到快速求出D(aj)D(a_j)的目的。

假設一個置換有 kk 個循環,易知每個循環對應的所有位置顏色需一致,而任意兩個循環之間選什麼顏色互不影響。因此,如果有m種可選顏色,則該置換對應的不動點個數爲 mkm^k 。用其替換BurnSide引理中的D(aj)D(a_j),得到等價類數目爲:
  
L=1G(mc(g1)+mc(g2)+...+mc(g2))L =\frac{1}{|G|}(m^{c(g_1)}+m^{c(g_2)}+...+m^{c(g_2)})

mc(gi)m^{c(g_i)}爲第ii個置換的循環個數。

總結一下:

Polya定理就是用(染色顏色^循環節數)求和 來替代 Burnside中的不動點個數

各個置換下不動點個數的和 = 染色顏色^循環節數的和

所以我們解決 求等價類 個數的問題就轉化成了兩個主要問題:

  1. 構造置換羣
  2. 計算置換羣中每個置換的循環節數 並求和。

下面是一道經典例題:
POJ 1286 Necklace of Beads

題意

給出三種顏色紅綠藍,對一串n個小球的環染色,環可以旋轉和翻轉,問最終可能有多少不同的染色方案。

思路

按照我們上面描述的那樣,我們先解決第一個問題:構造我們的置換羣。

分析題目,我們可以有 n個小球,3種顏色,我們可以通過旋轉來找到本質相同的染色方案,但這樣就結束了嗎? 並沒有,我們來看下面這個例子:

在這裏插入圖片描述
面對圖中的情況,我們通過旋轉是沒有辦法找到兩個本質相同的方案,所以還需要考慮翻轉的問題。

到此我們知道,可以把我們的置換主要分爲兩類:

  1. 旋轉 : 旋轉 ii 個小球的距離,那麼會得到 0n10~n-1 的置換方案,共有nn種。 旋轉 ii 個小球,我們的第 jj個小球就轉到了 第 lab[j] 個位置 。lab[j] = (i + j) % n + 1;
  2. 翻轉:其實就是將對稱的位置交換,第 j 個 位置第 n + 1 - j 個位置交換。

解決了置換羣的構造問題,那麼下一步就是 計算出循環節數的問題。
首先使用一種樸素的計算循環節數的方法,就是直接模擬我們手算循環節數的過程。

樸素循環節求法:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#define ll long long 
using namespace std;

const int N = 30;
int lab[N];
bool vis[N] = {0};
int n;

//快速冪
ll qpow(ll a, ll b){
	ll res = 1;
	while(b){
		if(b & 1){
			res *= a;
		}
		a *= a;
		b >>= 1;
	}
	return res;
}
//計算循環節數
ll get_loop(){
	ll cnt = 0;
	memset(vis,0,sizeof(vis));
	for(int i = 1; i <= n; i++){
		if(vis[i]) continue;
		cnt++;
		int j = i;
		do{
			vis[j] = true;
			j = lab[j];	
		}while(!vis[j]);
	}
	return cnt;
} 
int main(){
	while(cin>>n){
		//printf("No smoking!");
		if(n == -1) break; 
		ll ans = 0;  
		if(n < 1){
			puts("0");
			continue;
		}
		for(int i = 0; i < n; i++){
			//旋轉
			for(int j = 1; j <= n; j++) lab[j] = (i + j) % n + 1;
			ans += qpow(3,get_loop());
			//翻轉
			for(int j = 1; j <= n / 2; j++) swap(lab[j],lab[n + 1 - j]);
			ans += qpow(3,get_loop());
		}
		printf("%lld\n",ans/(n*2));
	}
	return 0;
}

前人總結了一些關於循環節的一些結論:

①旋轉。有n種置換,分別是1次旋轉1個珠子,2個,3個…n個。對於1次旋轉i個珠子,我們要求出循環節數可以先求出循環長度,一個位置置換x次之後回到原位,所以x=ny/i,要使x儘量小且爲整數那麼ny只能是lcm(n,i),於是循環長度爲lcm(n,i)/i,那麼循環節數爲總長除以循環長度,n/(lcm(n,i)/i)=gcd(n,i)【n*i/gcd(n,i)=lcm(n,i)】。所以1次旋轉i個珠子的循環節數爲gcd(n,i)。

②翻轉。對於奇偶性分類討論。

(1)n爲奇數。對於每個點作爲對稱軸左右翻轉,則共n個置換,循環節數(n+1)/2。

(2)n爲偶數。

a.對於對稱的兩個點作爲對稱軸左右翻轉。n/2個置換,循環節數(n+2)/2。

b.對於兩個點中間的空格作爲對稱軸左右反轉,n/2個置換,循環節數n/2。

則共n個置換。

所以不論奇偶總置換數爲2n,答案爲sum/2n。
.
———— 以上結論來自博客https://www.cnblogs.com/Sakits/p/6985058.html

下面給出一些簡要證明:

①旋轉

設當前的位置是 pp,我們一次旋轉 xx 個位置,假設我們旋轉了 kk 次到了原位置。

那麼我們就有
p+kxp(mod n)p+kx\equiv p(mod \ n)
兩邊同時減去pp,可以得到
kx0(mod n)kx\equiv 0(mod \ n)
可以知道 n  kxn\ |\ kx,又因爲 x  kxx\ |\ kx,但是我們求的是循環節長度,即 kk 需要最小,又因爲 xx 是常量,那麼我們當然取 nnxx 的最小公倍數了。
kx=lcm(n,x)kx = lcm(n,x)
又因爲 lcm(n,x)=nxgcd(n,x)\displaystyle lcm(n,x)=\frac{nx}{gcd(n,x)}
可以得到kx=lcm(n,x)=nxgcd(n,x) k=ngcd(n,x)\displaystyle kx = lcm(n,x)=\frac{nx}{gcd(n,x)}\\\ \\\\k = \frac{n}{gcd(n,x)}
因爲循環節的長度爲ngcd(n,x)\displaystyle \frac{n}{gcd(n,x)},又一共有nn個元素,且這nn個元素對稱,那麼顯然循環節個數就是gcd(n,x)gcd(n,x)

②翻轉

(1)奇數個點

奇數個點,對稱軸肯定是經過某一個點,(下圖的藍點),那麼,每一對 對稱的點 就形成了一個循環節 。

以下圖爲例,藍色點爲對稱的點,綠點和紅點是一個循環節,黃色和橙色是一個循環節 ,藍色是不動點 本身是一個循環節。所以一共是n12+1=n+12\displaystyle\frac{n-1}{2}+1=\frac{n+1}{2}個循環節。
在這裏插入圖片描述
(2)偶數個點
偶素有兩種對稱的可能

  1. 對稱軸過其中兩點
    在這裏插入圖片描述22 個不動點,剩下的 n2n-2 每兩個點成一個循環節,共n22+2=n+22\displaystyle\frac{n-2}{2}+2=\frac{n+2}{2}個。
  2. 對稱軸在兩點間的空格
    在這裏插入圖片描述每兩個點成一個循環節,共n2\displaystyle\frac{n}{2}個。

下面是運用結論求法

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#define ll long long 
using namespace std;

const int N = 30;
int lab[N];
bool vis[N] = {0};
int n;
//最大共約數
ll gcd(ll a, ll b){
	return b == 0 ? a : gcd(b,a % b);
} 

//快速冪 
ll qpow(ll a, ll b){
	ll res = 1;
	while(b){
		if(b & 1){
			res *= a;
		}
		a *= a;
		b >>= 1;
	}
	return res;
}
int main(){
	while(cin>>n){
		//printf("No smoking!");
		if(n == -1) break; 
		ll ans = 0;  
		if(n < 1){
			puts("0");
			continue;
		}
		//旋轉置換 
		for(int i = 1; i <= n; i++)
			ans += qpow(3,gcd(i,n));
		//對稱置換 
		if(n&1) {
            ans+=qpow(3,n/2+1)*n;
        } else {
            ans+=qpow(3,n/2+1)*(n/2);
            ans+=qpow(3,n/2)*(n/2);
        }
		printf("%lld\n",ans/(n*2));
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章