题目分析:
给定可选数序列a(n个数)1<=n<=20 2<= a[i] <=20
我们和对方轮流选数,当前轮到我们。
状态压缩:①n位二进制数x(0代表可选,1代表不可选)
②轮到谁turn (turn=true轮到我们 反之轮到对方)
状态存储:int state[maxX][2] maxX为2^20左右的数 ,用于存状态 x 下的两种情况:turn=true turn=false
state[x][turn]= -1 代表该状态为“输状态(对方赢)”
=1 代表是赢状态
=0 代表是初始状态,还没求
初始状态:x=0,turn=true
出口状态:① x=2^n-1 , turn = true =》 state [ x ][ turn ]= -1
② x=2^n-1 , turn = false =》 state[ x ][ turn ]=1
普通状态:对每一个当前状态下可选的数 {
选中该数,根据题目描述,获取下一状态nextX(即去掉所有不满足的数)
如果state [nextX][ !turn ]还未求值,则递归求值:dfs(nextX,!turn)
获取state [nextX][ !turn ]的值
}
根据以上循环中所有state [nextX][ !turn ]判断当前状态 [x,turn]
① turn=true
只需以上循环中存在一个state [nextX][ !turn ]=1 则当前状态为赢状态
否则为输状态。
(因为,轮到我方走的时候,我们可以自主选择要选的数,这样,当前只要有
一个能使下一状态为赢状态的数就可以了,我们选择它就一定可以赢,所以
当前状态为赢状态)
② turn=false
需要循环中的state [nextX][ !turn ]都等于 1,当前状态才是赢状态
否则为输状态
(因为当前状态轮到对方,只要存在一个state [nextX][ !turn ]= -1,
那么对方只要选这个数,就可以赢过我们,当前状态就不是赢状态)
代码:
#include<iostream> #include<map> #include<set> #include<cmath> using namespace std; int n=-1; const int maxn = 21; int a[maxn]; const int maxX = 1800000; int state[maxX][2]; set<int> re; void ini() { for (int i = 0;i < maxX;i++) { state[i][0] = state[i][1] = 0; } re.clear(); } bool isAvail(int x, int i) { bool re = x&(1 << i); return !re; } bool isNotAva(int x,int sec,int i) { i = a[i]; sec = a[sec]; if (i%sec == 0)return true; if (i < sec)return false; else { int tmp = sec; while (tmp < i) { int k = i - tmp; if (k == 1)return false; bool f = false; for (int j = 0;j < n;j++) { if (a[j] == k) { f = true; break; } } if (!f)return true; for (int j = 0;j < n;j++) { if (!isAvail(x, j)) { if (k%a[j] == 0)return true; } } tmp += sec; } } return false; } int nextState(int x,int i) { int re = x | (1 << i); for (int j = 0;j < n;j++) { if (isAvail(re, j)) { if (isNotAva(re, i, j)) { re = re | (1 << j); } } } return re; } void dfs(int x,bool turn) { if (x == (int)pow(2.0,n) - 1) { if(turn)state[x][turn] = -1; else state[x][turn] = 1; return; } bool flag = true, flag2 = false; for (int j = 0;j < n;j++) { if (isAvail(x, j)) { int nextX = nextState(x, j); if (state[nextX][!turn] == 0) { dfs(nextX, !turn); } if (state[nextX][!turn] != 1) { flag = false; } else flag2 = true; if (state[nextX][!turn] == 1 && x == 0) { re.insert(j); } } } if (x!=0) if (turn) { if (flag2)state[x][turn] = 1; else state[x][turn] = -1; } else { if (flag) { state[x][turn] = 1; }else state[x][turn] = -1; } } int main() { int c = 1; while (n != 0) { scanf("%d", &n); if (n == 0)break; for (int i = 0;i < n;i++) { scanf("%d", &a[i]); } ini(); dfs(0, true); printf("Test Case #%d\n", c); if (re.size() != 0) { int co = 1; printf("The winning moves are: "); set<int>::iterator it = re.begin(); while (it!=re.end()) { printf("%d", a[*it]); if (co < re.size())printf(" "); co++; it++; } } else printf("There's no winning move."); printf("\n\n"); c++; } return 0; }