2010-1076

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

== 题目大意 ==

桌面上有 4 张牌,两个拥有不太一样的换牌技能的人博弈,其中一个人的目的是让 4 张牌可以算出 24 点,另一个人是不让 4 张牌算出 24 点,问对于一个人,有无必胜策略。

== 简要算法 ==

算法分为两个步骤:
 1.  打表,暴力算出所有可能的 24 点情况,这个步骤大概需要 0.1 s
 2. 博弈,暴力搜索所有情况,按照比赛时使用的数据,这个步骤大约需要 0.1 s

== 参考程序 ==

这个版本的参考程序目前是 192 中已提交中最快的:

{{{
#!cpp
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <bitset>

using namespace std;

bitset<65536> v24;

inline double binop(double a, double b, int op) {
    switch(op) {
    case 0: return a + b;
    case 1: return a - b;
    case 2: return b - a;
    case 3: return a * b;
    case 4: return a / b;
    case 5: default: return b / a;
    }
}
inline bool t24(double a) {
    return a > 23.99999 and a < 24.00001;
}
void i24() {
    int a[5] = { 1 };
    int op[3];
#define FORA(i) for (a[i] = 1; a[i] < 11; a[i]++)
#define FOROP(i) for (op[i] = 0; op[i] < 6; op[i]++)
#define OP binop
    FORA(1) FORA(2) FORA(3) FORA(4) {
        int b[4] = {a[1], a[2], a[3], a[4]};
        sort(b, b + 4);
        int v = (b[0] + (b[1] << 4) + (b[2] << 8) + (b[3] << 12));
        if (v24.test(v)) continue;
        bool success = false;
        FOROP(0) FOROP(1) FOROP(2) 
            if  (
                t24(OP(OP(OP(a[1], a[2], op[0]), a[3], op[1]), a[4], op[2]))
                || t24(OP(OP(a[1], a[2], op[0]), OP(a[3], a[4], op[1]), op[2]))
                ) {
                success = true;
                goto i24_setbit;
            }
i24_setbit:
        if (success) v24.set(v);
    }
#undef FORA
#undef FOROP
}

struct Card {
    int n;
    char c;
    void read() {
        scanf("%d %c", &n, &c);
    }
};

struct State {
    Card d[4], p[2][4];
    const bool test() const {
        int ihc[4] = { d[0].n, d[1].n, d[2].n, d[3].n };
        sort(ihc, ihc + 4);
        int v = (ihc[0] + (ihc[1] << 4) + (ihc[2] << 8) + (ihc[3] << 12));
        return (v24.test(v) != 0);
    }
} state;

int k,m;
// return true if Sima Yi wins
bool gao(int who = 0, bool first_round = false) {
    // set win to 24 judge from desktop currently
    bool win = state.test(); 

    if (who) {
        // Zhang Jiao's turn, he wins if there is one way to win
        if (!win) return win;
        for (int i = 0; i < m; i++) {
            Card card = state.p[who][i];
            if (card.c == 'b') {
                // can use that card to swap a card in desktop
                for (int j = 0; j < 4; j++) {
                    // backup card at desktop and swap
                    Card card_backup = state.d[j];
                    state.d[j] = card;
                    state.p[who][i] = card_backup;
                    if (!gao(who ^ 1)) {
                    state.p[who][i] = card;
                    state.d[j] = card_backup;
                        return win = false;
                    }
                    // resume cards
                    state.p[who][i] = card;
                    state.d[j] = card_backup;
                }
            }
        }
    } else {
        if (first_round) win = false;
        if (win) return win;
        // Si Mayi's turn, he will win if there is just one way to win
        for (int i = 0; i < k; i++) {
            Card card = state.p[who][i];
            if (card.n > 0) {
                state.p[who][i].n = -1;
                // use that card to replace a card in desktop
                for (int j = 0; j < 4; j++) {
                    Card card_backup = state.d[j];
                    state.d[j] = card;
                    if (gao(who ^ 1)) {
                        state.d[j] = card_backup;
                        state.p[who][i] = card;
                        return win = true; 
                    }
                    state.d[j] = card_backup;
                }
                // resume that card
                state.p[who][i] = card;
            }
        }
    }
    return win;
}

int main(int argc, char const* argv[])
{
    // init 24, 0.13 s
    i24();

    int tc;
    scanf("%d", &tc);
    for (int ti = 0; ti < tc; ti++) {
        for (int i = 0; i < 4; i++)  state.d[i].read();
        scanf("%d%d", &k, &m);
        for (int ki = 0; ki < k; ki++) state.p[0][ki].read();
        for (int mi = 0; mi < m; mi++) state.p[1][mi].read();

        if (gao(0, true) || gao(1)) puts("Sima Yi Wins!");
        else puts("Zhang Jiao Wins!");
    }
    return 0;
}
}}}

题目大意

桌面上有 4 张牌,两个拥有不太一样的换牌技能的人博弈,其中一个人的目的是让 4 张牌可以算出 24 点,另一个人是不让 4 张牌算出 24 点,问对于一个人,有无必胜策略。

简要算法

算法分为两个步骤:

1. 打表,暴力算出所有可能的 24 点情况,这个步骤大概需要 0.1 s

2. 博弈,暴力搜索所有情况,按照比赛时使用的数据,这个步骤大约需要 0.1 s

参考程序

这个版本的参考程序目前是 192 中已提交中最快的:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <bitset>
using namespace std;
bitset<65536> v24;
inline double binop(double a, double b, int op) {
    switch(op) {
    case 0: return a + b;
    case 1: return a - b;
    case 2: return b - a;
    case 3: return a * b;
    case 4: return a / b;
    case 5: default: return b / a;
    }
}
inline bool t24(double a) {
    return a > 23.99999 and a < 24.00001;
}
void i24() {
    int a[5] = { 1 };
    int op[3];
#define FORA(i) for (a[i] = 1; a[i] < 11; a[i]++)
#define FOROP(i) for (op[i] = 0; op[i] < 6; op[i]++)
#define OP binop
    FORA(1) FORA(2) FORA(3) FORA(4) {
        int b[4] = {a[1], a[2], a[3], a[4]};
        sort(b, b + 4);
        int v = (b[0] + (b[1] << 4) + (b[2] << 8) + (b[3] << 12));
        if (v24.test(v)) continue;
        bool success = false;
        FOROP(0) FOROP(1) FOROP(2) 
            if  (
                t24(OP(OP(OP(a[1], a[2], op[0]), a[3], op[1]), a[4], op[2]))
                || t24(OP(OP(a[1], a[2], op[0]), OP(a[3], a[4], op[1]), op[2]))
                ) {
                success = true;
                goto i24_setbit;
            }
i24_setbit:
        if (success) v24.set(v);
    }
#undef FORA
#undef FOROP
}
struct Card {
    int n;
    char c;
    void read() {
        scanf("%d %c", &n, &c);
    }
};
struct State {
    Card d[4], p[2][4];
    const bool test() const {
        int ihc[4] = { d[0].n, d[1].n, d[2].n, d[3].n };
        sort(ihc, ihc + 4);
        int v = (ihc[0] + (ihc[1] << 4) + (ihc[2] << 8) + (ihc[3] << 12));
        return (v24.test(v) != 0);
    }
} state;
int k,m;
// return true if Sima Yi wins
bool gao(int who = 0, bool first_round = false) {
    // set win to 24 judge from desktop currently
    bool win = state.test(); 
    if (who) {
        // Zhang Jiao's turn, he wins if there is one way to win
        if (!win) return win;
        for (int i = 0; i < m; i++) {
            Card card = state.p[who][i];
            if (card.c == 'b') {
                // can use that card to swap a card in desktop
                for (int j = 0; j < 4; j++) {
                    // backup card at desktop and swap
                    Card card_backup = state.d[j];
                    state.d[j] = card;
                    state.p[who][i] = card_backup;
                    if (!gao(who ^ 1)) {
                    state.p[who][i] = card;
                    state.d[j] = card_backup;
                        return win = false;
                    }
                    // resume cards
                    state.p[who][i] = card;
                    state.d[j] = card_backup;
                }
            }
        }
    } else {
        if (first_round) win = false;
        if (win) return win;
        // Si Mayi's turn, he will win if there is just one way to win
        for (int i = 0; i < k; i++) {
            Card card = state.p[who][i];
            if (card.n > 0) {
                state.p[who][i].n = -1;
                // use that card to replace a card in desktop
                for (int j = 0; j < 4; j++) {
                    Card card_backup = state.d[j];
                    state.d[j] = card;
                    if (gao(who ^ 1)) {
                        state.d[j] = card_backup;
                        state.p[who][i] = card;
                        return win = true; 
                    }
                    state.d[j] = card_backup;
                }
                // resume that card
                state.p[who][i] = card;
            }
        }
    }
    return win;
}
int main(int argc, char const* argv[])
{
    // init 24, 0.13 s
    i24();
    int tc;
    scanf("%d", &tc);
    for (int ti = 0; ti < tc; ti++) {
        for (int i = 0; i < 4; i++)  state.d[i].read();
        scanf("%d%d", &k, &m);
        for (int ki = 0; ki < k; ki++) state.p[0][ki].read();
        for (int mi = 0; mi < m; mi++) state.p[1][mi].read();
        if (gao(0, true) || gao(1)) puts("Sima Yi Wins!");
        else puts("Zhang Jiao Wins!");
    }
    return 0;
}