感谢 Owaski 的帮助!
设 G 是 p 个对象的一个置换群, S 为不同染色方案数
Burnside引理:
令D(a) 表示在置换 a 下不变的元素的个数
S=∑D(i)|G|
Polya定理:
如果用 m种颜色涂染 p个对象
令 C(a) 表示置换 a 中的循环节数
S=∑mC(i)|G|
时间复杂度为 O(|G|∗p)
http://blog.youkuaiyun.com/qq_20118433/article/details/44220365
在本题中,p=n∗m ,
|G|=n∗m∗4 | n=m , n∗m∗2 | n≠m
Polya 完全可以胜任,时间复杂度 O((n∗m)2)
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn = 23, maxm = 25, maxl = 100;
const int Base = 1e4, Blen = 4;
struct BigNum
{
int num[maxl], l;
void plus(int &hp,int &tp)
{
hp += tp/Base, tp %= Base;
}
void digit()
{
for(int i = 1; i <= l; i++) plus(num[i+1] ,num[i]);
while(num[l+1]) ++l, plus(num[l+1], num[l]);
}
void operator +=(const BigNum &add)
{
l = std::max(l, add.l);
for(int i = 1; i <= l; i++)
num[i] += add.num[i];
digit();
}
void operator /=(const int x)
{
int nl = 0;
for(int i = l; i > 0; i--)
{
num[i-1] += num[i]%x*Base, num[i] /= x;
if(!nl && num[i]) nl = i;
}
l = nl;
}
void prt()
{
printf("%d",num[l]);
for(int i = l-1; i > 0; i--)
printf("%04d",num[i]);
}
};
int n, m;
bool square;int G;
int f[maxn*maxm];
BigNum pow2[maxn*maxm];
BigNum ans;
void PreWork()
{
if(square = (n == m))
G = (n*m)<<2;
else
G = (n*m)<<1;
pow2[0].l = pow2[0].num[1] = 1;
for(int i = 1; i <= n*m; i++)
pow2[i] = pow2[i-1], pow2[i] += pow2[i-1];
}
void Slide_Down()
{
static int tmp[maxn*maxm];
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
tmp[i%n*m+j] = f[(i-1)*m+j];
for(int i = 1; i <= n*m; i++) f[i] = tmp[i];
}
void Slide_Right()
{
static int tmp[maxn*maxm];
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
tmp[(i-1)*m+j%m+1] = f[(i-1)*m+j];
for(int i = 1; i <= n*m; i++) f[i] = tmp[i];
}
void Rotate()
{
static int tmp[maxn*maxm];
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
tmp[(j-1)*n+n-i+1] = f[(i-1)*m+j];
for(int i = 1; i <= n*m; i++) f[i] = tmp[i];
std::swap(n, m);
}
int calc()
{
static bool hash[maxn*maxm];
memset(hash,false,sizeof(hash));
int cnt = 0;
for(int i = 1; i <= n*m; i++)
for(int j = i; !hash[j]; j = f[j])
{
if(i == j) cnt++;
hash[j] = true;
}
return cnt;
}
void Polya()
{
for(int i = 1; i <= n*m; i++) f[i] = i;
for(int i = 1; i <= n; i++, Slide_Down())
for(int j = 1; j <= m; j++, Slide_Right())
{
ans += pow2[calc()];
Rotate();
if(square) ans += pow2[calc()];
Rotate();
ans += pow2[calc()];
Rotate();
if(square) ans += pow2[calc()];
Rotate();
}
ans /= G;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("sgu208.in","r",stdin);
freopen("sgu208.out","w",stdout);
#endif
std::cin >> n >> m;
PreWork(), Polya();
ans.prt();
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
#endif
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
本文详细介绍了如何使用Burnside引理和Polya定理解决染色方案计数问题,通过具体算法实现,展示了在给定置换群和染色条件下,计算不同染色方案数量的方法。时间复杂度为O((n*m)^2),适用于n=m和n≠m的情况。
953

被折叠的 条评论
为什么被折叠?



