解题报告:有n(1<=n<=4)个立方体,每个立方体的每一个面涂有一种颜色,现在要将这些立方体的某些面的颜色重新涂一下,使得这n个立方体旋转到某一种状态下,对应的面的颜色都相同。
这题可以用暴力。现在首先要研究的是一个立方体可以有多少种旋转的方式,假设经过一次旋转之后,立方体变成一种新的状态,我们把这种状态叫做姿态,题目中将每个面编了号,我们可以这样来说明一种姿态,就是说假设上面的那个面的编号为x,并且前面的那个编号为y,这样就可以唯一地确定这种姿态了,假设把题开始的那种状态向左转一次,那么
就得到上面的编号为3,前面的编号为6,这样就确定了一种姿态,这种姿态可以被描述为{5,1,3,4,6,2},按照这样的方法,很明显可以枚举出24种不同的姿态,当然,你也可以通过程序来确定这24种状态是怎么样的。列举出来的24种状态如下:
{2,1,5,0,4,3},{2,0,1,4,5,3},{2,4,0,5,1,3},{2,5,4,1,0,3},{4,2,5,0,3,1},
{5,2,1,4,3,0},{1,2,0,5,3,4},{0,2,4,1,3,5},{0,1,2,3,4,5},{4,0,2,3,5,1},
{5,4,2,3,1,0},{1,5,2,3,0,4},{5,1,3,2,4,0},{1,0,3,2,5,4},{0,4,3,2,1,5},
{4,5,3,2,0,1},{3,4,5,0,1,2},{3,5,1,4,0,2},{3,1,0,5,4,2},{3,0,4,1,5,2},
{1,3,5,0,2,4},{0,3,1,4,2,5},{4,3,0,5,2,1},{5,3,4,1,2,0}};
下一步我们就该讨论枚举这n个立方体每个立方体有24种姿态,然后分别求出每种不同的姿态需要重新涂颜色的最少的数量。可以用一个dfs来枚举出每个立方体的姿态,这样最多要枚举的次数就是24^4。然后就是如何计算每一种情况下最少应该重新涂改的颜色的个数,我们可以先分成6个面,然后计算这个可以另外写一个函数来判断,我的做法是将每个立方体的对应的面的颜色先存到一个字符串数组里面去,然后求出这些颜色里面哪一种是最多的,然后再看如果跟这个最多的颜色是不同的话就让计数器加1,最后得到的就是这个面应该修改的总的数量,然后按照同样的方式把每个面的加起来就可以了。
#include<iostream>
#include<cstdio>
#include<cstring> using namespace std;
char map[][][];
int kase[][]={
{,,,,,},{,,,,,},{,,,,,},{,,,,,},{,,,,,},
{,,,,,},{,,,,,},{,,,,,},{,,,,,},{,,,,,},
{,,,,,},{,,,,,},{,,,,,},{,,,,,},{,,,,,},
{,,,,,},{,,,,,},{,,,,,},{,,,,,},{,,,,,},
{,,,,,},{,,,,,},{,,,,,},{,,,,,}};
const int MAX = 0xffffff;
int Min = MAX,n,dire[];
int panduan(char p[][]) {
int a[]={};
for(int i=;i<n;++i)
for(int j=;j<n;++j)
if(!strcmp(p[i],p[j]))
a[i]++;
int Max=;
for(int i=;i<n;++i)
if(a[i]>a[Max])
Max=i;
int tot=;
for(int i=;i<n;++i)
if(strcmp(p[i],p[Max]))
tot++;
return tot;
}
void Cube() {
int sum=;
for(int m=;m<;++m) {
char bijiao[][]; //改成动态分配内存,否则容易出错
for(int p=;p<n;++p)
strcpy(bijiao[p],map[p][kase[dire[p]][m]]);
sum += panduan(bijiao);
}
if(sum<Min)
Min = sum;
}
void dfs(int deep) {
if(deep == n-)
Cube();
else
for(int i=;i<;++i) {
dire[deep] = i;
dfs(deep+);
}
}
int main() {
while(scanf("%d",&n)&&n) {
for(int i=;i<n;++i)
for(int j=;j<;++j)
scanf("%s",map[i][j]);
Min = MAX;
dfs();
printf("%d\n",Min);
}
return ;
}