UVA1352 Colored Cubes

发布于 2020-08-16  1.55k 次阅读


题面

题意

告诉你若干立方体每个面的颜色,让你在所有立方体上重新染尽可能少的面以使得最终这些立方体完全一样,即对应面颜色均相同。(包括立方体以任意方向摆放时相同)

解法

如题意模拟,代码有一定难度。

我们先使用dfs来枚举出每一个立方体摆放的方向,然后在确定完 $n$ 个立方体的摆放方向后,对于每一个面,找到最优的颜色并且把所有立方体的该面都染成上述颜色,最后统计答案即可。

这里我写了一个 near(i,j) 的函数来帮助我计算当立方体以 $i$ 面向前, $j$ 面向上时左面的编号。(在考场上我手造了一个小立方体搓了半天搓出来的)你也同样可以使用预处理方向矩阵的方式来代替这一操作。

详情见代码。

代码

#include <bits/stdc++.h>
using namespace std;

#define oppo(i) (5 - i)
//oppo(i)即为立方体上i对面的面

map<string, int> has;  //哈希

int rec[5][8],  //记录每个立方体每个面的颜色
    vis[5][8];  //表示当前dfs状态下前后左右上下分别对应原立方体的哪个面
int bucket[30];
int n, answer;

int near(int i, int j) {  //求出夹在i与j之间的面
    if (i == 1)
        if (j == 2)
            return 3;
        else if (j == 3)
            return 5;
        else if (j == 5)
            return 4;
        else
            return 2;
    else if (i == 2)
        if (j == 1)
            return 4;
        else if (j == 4)
            return 6;
        else if (j == 6)
            return 3;
        else
            return 1;
    else if (i == 3)
        if (j == 1)
            return 2;
        else if (j == 2)
            return 6;
        else if (j == 6)
            return 5;
        else
            return 1;
    else if (i == 4)
        if (j == 1)
            return 5;
        else if (j == 5)
            return 6;
        else if (j == 6)
            return 2;
        else
            return 1;
    else if (i == 5)
        if (j == 1)
            return 3;
        else if (j == 3)
            return 6;
        else if (j == 6)
            return 4;
        else
            return 1;
    else if (j == 2)
        return 4;
    else if (j == 4)
        return 5;
    else if (j == 5)
        return 3;
    else
        return 2;
}

void dfs(int depth) {
    if (depth == n) {  //如果n个立方体的方向都已确定
        int tot = 0;
        for (int i = 0; i < 6; i++) {
            memset(bucket, 0, sizeof(bucket));  //使用桶来记录所有该面出现过的颜色数量
            for (int j = 0; j < n; j++)
                bucket[rec[j][vis[j][i]]]++;
            int ans = bucket[1];
            for (int j = 2; j < 30; j++)
                ans = max(ans, bucket[j]);  //取出现次数最多的颜色数量
            tot += n - ans;                 //用总量减去该颜色数量即为最优解
        }
        answer = min(answer, tot);
        return;
    }
    for (int i = 0; i < 6; i++)  //枚举当前立方体的方向
        for (int j = 0; j < 6; j++)
            if (j != i && j != oppo(i)) {
                int k = near(i + 1, j + 1) - 1;
                vis[depth][0] = i, vis[depth][1] = j, vis[depth][2] = k,  //确定每一个面与原立方体的关系
                    vis[depth][3] = oppo(k), vis[depth][4] = oppo(j), vis[depth][5] = oppo(i);
                dfs(depth + 1);
            }
}

int main() {
    ios::sync_with_stdio(false);
    while ((cin >> n) && n) {
        int cnt = 0;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < 6; j++) {
                string face;
                cin >> face;
                if (has.find(face) == has.end())  //hash
                    has[face] = ++cnt;
                rec[i][j] = has[face];
            }
        answer = 0x3f3f3f3f;
        dfs(0);
        printf("%d\n", answer);
        has.clear();
    }
    return 0;
}

我缓慢吐出一串啊吧啊吧并不再想说话