【UVa10601】Cubes-Burnside引理应用
测试地址:Cubes
题目大意:给你12根长度相同的棒子,每根棒子都有颜色,颜色不超过6种,问可以组成的本质不同的立方体的数量。我们说两个立方体本质不同,当且仅当如何旋转它们都不能使它们的着色方案重合。
做法:这一题需要使用Burnside引理来解决。
首先介绍Burnside引理:设
我们知道对于某一个置换
回到这一题里,我们要考虑两个难点:1.如何求出置换群;2.如何求出每个置换的
要求出符合本题要求的置换群,就要搞清楚立方体有什么不同的旋转方式。综合来看可以分为以下四种:
第一种是静止不动,这样只有一种情况,置换的循环数是
第二种是以一条对角线为轴旋转,立方体有
第三种是以一对相对的棱的中点连线为轴旋转,立方体有
第四种是以一对相对的面的中点连线为轴旋转,立方体有
综上所述,我们要求的置换群
然后第二个问题,就是怎么求各个置换的
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
ll T,c[10],ans,fac[20];
ll solve(int p,int q)
{
ll s=1;
for(int i=1;i<=6;i++)
if (c[i]%q!=0) return 0;
for(int i=1;i<=6;i++)
s*=fac[c[i]/q];
return fac[p]/s;
}
void solve_still()
{
ans+=1*solve(12,1);
}
void solve_plane()
{
ans+=3*2*solve(3,4)+3*1*solve(6,2);
}
void solve_edge()
{
for(int i=1;i<=6;i++)
if (c[i]>0)
{
c[i]--;
for(int j=1;j<=6;j++)
if (c[j]>0)
{
c[j]--;
ans+=6*1*solve(5,2);
c[j]++;
}
c[i]++;
}
}
void solve_point()
{
ans+=4*2*solve(4,3);
}
int main()
{
scanf("%lld",&T);
fac[0]=1;
for(int i=1;i<=12;i++)
fac[i]=fac[i-1]*i;
while(T--)
{
ans=0;
memset(c,0,sizeof(c));
for(int i=1,x;i<=12;i++)
{
scanf("%d",&x);
c[x]++;
}
solve_still();
solve_plane();
solve_edge();
solve_point();
printf("%lld\n",ans/24);
}
return 0;
}