Uva10601 Cubes

Description
You are given 12 rods of equal length. Each of them is colored in certain color. Your task is to determine in how many different ways one can construct a cube using these rods as edges. Two cubes are considered equal if one of them could be rotated and put next to the other, so that the corresponding edges of the two cubes are equally colored.
给定12根等长带有颜色小木棍,要组成一个正方体,如果一个正方体能通过一个正方体旋转得到,那么我们称这两个正方体是等价的。求本质不同的正方体个数

Input
The first line of input contains T (1≤T≤60), the number of test cases.
Then T test cases follow. Each test case consists of one line containing 12 integers.
Each of them denotes the color of the corresponding rod.
The colors are numbers between 1 and 6.

Output
The output for one test consists of one integer on a line - the number of ways one can construct a cube
with the described properties.

Sample Input
3
1 2 2 2 2 2 2 2 2 2 2 2
1 1 2 2 2 2 2 2 2 2 2 2
1 1 2 2 3 3 4 4 5 5 6 6

Sample Output
1
5
312120


对于本题而言,我们首先要找到有多少个置换数

对于一个正方体而言,它会有多少种置换方式呢?答案是24种

  • 不动置换,置换方式为1种
  • 以一对对顶点作为旋转轴,那么我们有120°,240°两种旋转方式,加上我们共有4对点,因此置换方式为 4*2=8 种
  • 以一对对面的中心点为旋转轴,那么我们有90°,180°,270°三种旋转方式,加上我们共有3对面,因此置换方式为 3*3=9 种
  • 以一对对棱的中点为旋转轴,那么我们只有180°这一种旋转方式,加上我们共有6对棱,因此置换方式为 1*6=6 种

所以总置换个数为 1+8+9+6=24 种

然后我们就需要用burnside引理来求出答案了,这点的话可以用组合数来弄弄即可。

注释一:如果以对点为旋转轴旋转,那么就是一些长度为3的循环,那么我们用组合数的时候要看看我所有的颜色是否能被3整除,如果不能被整除,那么就代表某个循环中,掺杂着一些不同的颜色,这些不同的颜色可以被那些循环较小的颜色给置换过来,因此这个情况是不合法的

注释二:由于对棱旋转时,会有两条边不动,那么我们就在枚举的时候减去即可

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
	int x=0,f=1;char ch=getchar();
	for (;ch<'0'||ch>'9';ch=getchar())	if (ch=='-')    f=-1;
	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<1)+(x<<3)+ch-'0';
	return x*f;
}
inline void print(int x){
	if (x>=10)     print(x/10);
	putchar(x%10+'0');
}
const int N=15;
ll C[N][N];
int A[7],B[7];
void prepare(){
	for (int i=0;i<N;i++){
		C[i][0]=C[i][i]=1;
		for (int j=1;j<i;j++)	C[i][j]=C[i-1][j-1]+C[i-1][j];
	}
}
ll work(int k){//注释一
	int n=0;
	for (int i=0;i<6;i++){
		if (B[i]%k)	return 0;
		B[i]/=k,n+=B[i];
	}
	ll Ans=1;
	for (int i=0;i<6;i++){
		Ans*=C[n][B[i]];
		n-=B[i];
	}
	return Ans;
}
ll stop_solve(){
	memcpy(B,A,sizeof(A));
	return work(1);
}
ll point_solve(){
	memcpy(B,A,sizeof(A));
	return 4*2*work(3); //循环节为3,有4对点,2种旋转方式
}
ll plane_solve(){
	memcpy(B,A,sizeof(A));
	ll Ans=3*2*work(4); //旋转90°与270°
	memcpy(B,A,sizeof(A));
	return Ans+=3*work(2);  //旋转180°
}
ll line_solve(){//注释二
	ll Ans=0;
	for (int i=0;i<6;i++){
		for (int j=0;j<6;j++){
			memcpy(B,A,sizeof(A));
			B[i]--,B[j]--;
			if (B[i]<0||B[j]<0)	continue;
			Ans+=6*work(2);
		}
	}
	return Ans;
}
ll solve(){
	ll Ans=0;
	Ans+=stop_solve();  //不动置换
	Ans+=point_solve(); //对点旋转
	Ans+=plane_solve(); //对面旋转
	Ans+=line_solve();  //对棱旋转
	return Ans/24;
}
int main(){
	prepare();
	for (int Data=read();Data;Data--){
		memset(A,0,sizeof(A));
		for (int i=1;i<=12;i++)	A[read()-1]++;
		printf("%lld
",solve());
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Wolfycz/p/8530806.html