uva 1558 - Number Game(状态压缩)

题目连接:uva 1558 - Number Game

题目大意:给定一些数,每次操作选取一个数x,然后剔除里面所有x的倍数,a+x的倍数(a为前面操作中剔除的数),最后不能操作的人为输。

解题思路:这题写的很乱,主要就是用一个二进制数表示有哪些数是还可以选的。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxs = (1<<20)-1;

int cnt, ans[30], dp[maxs+10];

int solve (int s, int x) {
    for (int i = x; i <= 20; i += x) {
        if (s&(1<<(i-2)))
            s ^= (1<<(i-2));
    }

    /* for (int i = 2; i + x < 20; i++) { if ( (s&(1<<(i-2))) == 0 && (s&(1<<(i+x-2))) ) s ^= (1<<(i+x-2)); } */
    for (int i = 2; i <= 20; i++) {
        if (s&(1<<(i-2))) {
            for (int j = x; i - j >= 2; j += x) {
                if (!(s&(1<<(i-j-2)))) {
                    s ^= (1<<(i-2));
                    break;
                }
            }
        }
    }
    return s;
}

bool dfs (int s) {

    if (dp[s] != -1)
        return dp[s];

    for (int i = 2; i <= 20; i++) {
        if ((s&(1<<(i-2))) && (dfs(solve(s, i)) == false))
            return dp[s] = 1;
    }

    return dp[s] = 0;
}

int main () {
    int cas;
    scanf("%d", &cas);
    for (int k = 1; k <= cas; k++) {
        int x, n, s = 0;
        memset(dp, -1, sizeof(dp));
        cnt = dp[0] = 0;

        scanf("%d", &n);
        for (int i = 0; i < n; i++) {
            scanf("%d", &x);
            s |= (1<<(x-2));
        }

        for (int i = 2; i <= 20; i++) {
            if ((s&(1<<(i-2))) && dfs(solve(s, i)) == false)
                ans[cnt++] = i;
        }

        printf("Scenario #%d:\n", k);
        if (cnt) {
            printf("The winning moves are:");
            for (int i = 0; i < cnt; i++)
                printf(" %d", ans[i]);
            printf(".\n");
        } else
            printf("There is no winning move.\n");
        printf("\n");
    }
    return 0;
}

你可能感兴趣的:(uva 1558 - Number Game(状态压缩))