题目大意:
给出n个正方体,然后n行表示每个正方体6个面的上色,问涂最少的面使得n正方体都相同(注意正方体是可以旋转的)。
解析:
首先写出正方体有24个旋转方式,然后以第一个正方体为标准,枚举剩下n - 1个正方体的状态,然后计算最小值。具体见代码注释。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <map>
using namespace std;
const int dice24[24][6] = { //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},
{1, 3, 5, 0, 2, 4}, {0, 3, 1, 4, 2, 5}, {4, 3, 0, 5, 2, 1}, {5, 3, 4, 1, 2, 0},
{3, 4, 5, 0, 1, 2}, {3, 5, 1, 4, 0, 2}, {3, 1, 0, 5, 4, 2}, {3, 0, 4, 1, 5, 2},
};
const int MAX = 4;
int n, dice[MAX][6] ,ans;
int cnt;
int r[MAX], color[MAX][6];
map<string,int> names;
int id(char name[]) {
string s(name);
if(names.count(s)) {
return names[s];
}
names[s] = cnt++;
return names[s];
}
void check() {
//保存旋转的颜色
for(int i = 0; i < n; i++) { //枚举所有保存的旋转
for(int j = 0; j < 6; j++) { //枚举旋转的面
color[i][dice24[r[i]][j]] = dice[i][j];
}
}
int tot = 0;
int cnt[MAX*6];
for(int j = 0; j < 6; j++) {
int Max = 0;
memset(cnt,0,sizeof(cnt));
for(int i = 0; i < n; i++) {
cnt[color[i][j]]++;
Max = max(Max,cnt[color[i][j]]);
}
tot += (n - Max);
}
ans = min(ans, tot);
}
void dfs(int cur) {
if(cur == n) {
check();
return ;
}
for(int i = 0; i < 24; i++) { //枚举24种状态
r[cur] = i;
dfs(cur+1);
}
}
int main() {
char name[30];
while(scanf("%d",&n) != EOF && n) {
names.clear();
cnt = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < 6; j++) {
scanf("%s",name);
dice[i][j] = id(name);
}
}
ans = n*6; //上界:所有的面都有颜色
r[0] = 0; //第一个立方体不旋转
dfs(1);
printf("%d\n",ans);
}
return 0;
}