题意:20之内的数字,每次可以选一个数字,然后它的倍数,还有其他已选数的倍数组合的数都不能再选,谁先不能选数谁就输了,问赢的方法
思路:利用dp记忆化去求解,要输出方案就枚举第一步即可,状态转移过程中,选中一个数字,相应的变化写成一个函数,然后就是普通的博弈问题了,必胜态之后必有必败态,必败态之后全是必胜态
代码:
#include <stdio.h> #include <string.h> const int N = 1050005; int t, n, w, start, dp[N], ans[25], an; int getnext(int state, int x) { for (int i = x; i <= 20; i += x) if (state&(1<<(i - 2))) state ^= (1<<(i - 2)); for (int i = 2; i <= 20; i++) { if (state&(1<<(i - 2))) { for (int j = x; i - j >= 2; j += x) { if (!(state&(1<<(i - j - 2)))) { state ^= (1<<(i - 2)); break; } } } } return state; } int dfs(int state) { if (dp[state] != -1) return dp[state]; if (state == 0) return dp[state] = 0; for (int i = 2; i <= 20; i++) { if (state&(1<<(i - 2))) { if (dfs(getnext(state, i)) == 0) return dp[state] = 1; } } return dp[state] = 0; } int main() { int cas = 0; scanf("%d", &t); memset(dp, -1, sizeof(dp)); while (t--) { start = 0; an = 0; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &w); start |= (1<<(w - 2)); } for (int i = 2; i <= 20; i++) { if (start&(1<<(i - 2))) { if (dfs(getnext(start, i)) == 0) ans[an++] = i; } } printf("Scenario #%d:\n", ++cas); if (an) { printf("The winning moves are:"); for (int i = 0; i < an; i++) printf(" %d", ans[i]); printf(".\n"); } else printf("There is no winning move.\n"); printf("\n"); } return 0; }
UVA 1558 - Number Game(博弈dp),布布扣,bubuko.com
原文地址:http://blog.csdn.net/accelerator_/article/details/37889953