mayoko’s diary

プロコンとかいろいろ。

AOJ 1181: 偏りのあるサイコロ

解法

実装するだけ。と言っても結構めんどくさいので実装方針を軽く書きます。

サイコロのクラスを作って,
init(t, f) … top と front を決めたらサイコロの状態を決定する
rotate(dir)…回転させる

というメソッドを用意しておきます。

これをやっておくと, シミュレーションがかなり楽です。

enum Dir {
    TOP,
    BOTTOM,
    FRONT,
    BACK,
    LEFT,
    RIGHT
};

int trans[6] = {-1, -1, 3, 1, 2, 0};
int memo[6][4] = {{3,5,4,2}, {3,1,4,6}, {1,2,6,5}, {1,5,6,2}, {1,3,6,4}, {2,4,5,3}};

class Dice {
public:
    Dice() {d.resize(6);}
    Dice(int top, int front) {
        d.resize(6);
        set(top, front);
    }
    int find(int num) const {
        for (int i = 0; i < 6; i++) if (num==d[i]) return i;
        assert(0);
        return -1;
    }
    int get(int dir) const {
        return d[dir];
    }
    void set(int top, int front) {
        d[TOP] = top;
        d[BOTTOM] = 7-top;
        d[FRONT] = front;
        d[BACK] = 7-front;
        int index = 0;
        for (; index < 4; index++) {
            if (memo[top-1][index] == front) break;
        }
        d[RIGHT] = memo[top-1][(index+1)%4];
        d[LEFT] = 7-d[RIGHT];
    }
    void rotate(int dir) {
        vector<int> nd = d;
        if (dir == 0) {
            nd[TOP] = d[LEFT];
            nd[LEFT] = d[BOTTOM];
            nd[BOTTOM] = d[RIGHT];
            nd[RIGHT] = d[TOP];
        }
        if (dir == 1) {
            nd[TOP] = d[FRONT];
            nd[FRONT] = d[BOTTOM];
            nd[BOTTOM] = d[BACK];
            nd[BACK] = d[TOP];
        }
        if (dir == 2) {
            nd[TOP] = d[RIGHT];
            nd[RIGHT] = d[BOTTOM];
            nd[BOTTOM] = d[LEFT];
            nd[LEFT] = d[TOP];
        }
        if (dir == 3) {
            nd[TOP] = d[BACK];
            nd[BACK] = d[BOTTOM];
            nd[BOTTOM] = d[FRONT];
            nd[FRONT] = d[TOP];
        }
        d = nd;
    }
private:
    vector<int> d;
};

const int MAX = 111;
int field[MAX][MAX][MAX];

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int n;
    while (cin >> n) {
        if (n==0) break;
        memset(field, 0, sizeof(field));
        for (int i = 0; i < n; i++) {
            int t, f;
            cin >> t >> f;
            Dice dice(t, f);
            int y = MAX/2, x = MAX/2;
            for (int h = MAX-1; h >= 0; ) {
                if (h==0) {
                    field[h][y][x] = dice.get(TOP);
                    break;
                }
                if (field[h-1][y][x] == 0) {
                    h--;
                    continue;
                }
                bool finish = true;
                for (int num = 6; num >= 4; num--) {
                    int d = dice.find(num);
                    if (d==BOTTOM || d==TOP) continue;
                    int dir = trans[d];
                    int ny = y+dy[dir], nx = x+dx[dir];
                    if (field[h-1][ny][nx] == 0) {
                        dice.rotate(dir);
                        h--;
                        y = ny; x = nx;
                        finish = false;
                        break;
                    }
                }
                if (finish) {
                    field[h][y][x] = dice.get(TOP);
                    break;
                }
            }
        }
        vector<int> ans(6);
        for (int y = 0; y < MAX; y++) for (int x = 0; x < MAX; x++) {
            for (int h = MAX-1; h >= 0; h--) {
                if (field[h][y][x] > 0) {
                    ans[field[h][y][x]-1]++;
                    break;
                }
            }
        }
        for (int i = 0; i < 6; i++) {
            cout << ans[i];
            if (i < 5) cout << " " ;
        }
        cout << endl;
    }
    return 0;
}