题意:有n个带颜色的立方体,每个立方体每个面都涂有一种颜色。要求重新涂尽量少的面,使得所有立方体完全相同。两个立方体完全相同是指存在一种旋转方式,使得这两个立方体对应面颜色完全一样。
很暴力的题。首先每个立方体经过旋转,只有24种不同的状态(先选一个面作为前面,6种选法,然后选一个面作为上面,4种选法。共6*4 = 24种)。而n最大只有4,而且两个立方体经过旋转可以完全相同的话,我们可以一个立方体不动作为参照。这样只需要枚举最多3个立方体的所有状态,也就是最多24^3种状态组合。然后每个状态下比较所有立方体的每个面,对于每个面找出颜色相同的面的最大值,这些面都不重新涂,而重新涂剩下与他们不同颜色的面。这样复杂度是O(24^(n - 1)*n*6)可以通过这个题。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
//定义24种状态的6个面编号,第二维0-5分别表示上、下、左、右、前、后面的编号
const int state[24][6] =
{
{1, 6, 2, 5, 3, 4}, {1, 6, 3, 4, 5, 2}, {1, 6, 5, 2, 4, 3}, {1, 6, 4, 3, 2, 5},
{6, 1, 2, 5, 4, 3}, {6, 1, 4, 3, 5, 2}, {6, 1, 5, 2, 3, 4}, {6, 1, 3, 4, 2, 5},
{2, 5, 6, 1, 3, 4}, {2, 5, 3, 4, 1, 6}, {2, 5, 1, 6, 4, 3}, {2, 5, 4, 3, 6, 1},
{5, 2, 1, 6, 3, 4}, {5, 2, 3, 4, 6, 1}, {5, 2, 6, 1, 4, 3}, {5, 2, 4, 3, 1, 6},
{3, 4, 2, 5, 6, 1}, {3, 4, 6, 1, 5, 2}, {3, 4, 5, 2, 1, 6}, {3, 4, 1, 6, 2, 5},
{4, 3, 2, 5, 1, 6}, {4, 3, 1, 6, 5, 2}, {4, 3, 5, 2, 6, 1}, {4, 3, 6, 1, 2, 5},
};
const int MAX = 30;
int n;
char cube[5][6][MAX];
map <string, int> ma[6];
void input()
{
for(int i = 0; i < n; i++)
{
for(int j = 0; j < 6; j++)
scanf("%s", cube[i][j]);
}
}
void solve()
{
int total = 1; //存储一共的状态组合
int ans = 24; //初始化最大值
for(int i = 1; i < n; i++) //i从1开始,第一个立方体不用旋转,作为参考系即可
total *= 24;
int cnt[6];
while(total--)
{
memset(cnt, 0, sizeof(cnt));
for(int i = 0; i < 6; i++)
ma[i].clear();
int temp = total;
for(int i = 0; i < n; i++)
{
int pos = temp%24; //24进制法求每个立方体的状态
temp /= 24;
for(int j = 0; j < 6; j++)
cnt[j] = max(cnt[j], ++ma[j][cube[i][state[pos][j] - 1]]); // -1是因为数组下标对应问题
}
int temp_ans = 0;
for(int i = 0; i < 6; i++)
temp_ans += n - cnt[i];
ans = min(ans, temp_ans);
}
printf("%d\n", ans);
}
int main()
{
while(scanf("%d", &n) && n != 0)
{
input();
solve();
}
return 0;
}