博弈思想,状态压缩后记忆化搜索,必胜状态的条件为自状态存在必败状态。
g++ 0ms ac c++wa 知道原因的留个言
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int vis[600005], a[25], p2[25], cnt, ans[25];
//一共2^19种状态,19位2进制记录,某位为0表示此位对应数仍可以取
int ch(int x, int d){ //取数字d后的状态
x|=p2[d-2];
for(int i=d+1; i<=20; i++){
if(x&p2[i-2-d])x|=p2[i-2];
}
return x;
}
bool dfs(int x){
if(vis[x]){
if(vis[x]==1)return true;
else return false;
}
for(int i=0; i<19; i++){
if(!(x&p2[i])){
if(!dfs(ch(x, i+2))){
vis[x]=1;
return true;
}
}
}
vis[x]=-1;
return false;
}
int main(){
//freopen("1.txt", "r", stdin);
int n, i, cas=1, t;
memset(vis, 0, sizeof(vis));
p2[0]=1;
for(i=1; i<20; i++)
p2[i]=p2[i-1]*2;
while(scanf("%d", &n)&&n){
cnt=0;
t=p2[19]-1;
printf("Test Case #%d\n", cas++);
for(i=0; i<n; i++){
scanf("%d", &a[i]);
t^=p2[a[i]-2];
}
for(i=0; i<n; i++){
if(!dfs(ch(t, a[i]))){
ans[cnt++]=a[i];
}
}
if(cnt){
printf("The winning moves are:");
for(i=0; i<cnt; i++)
printf(" %d", ans[i]);
printf("\n\n");
}
else printf("There's no winning move.\n\n");
}
return 0;
}