POJ:1143 Number Game

题意:两个人玩游戏,初始集合S为大于1的正整数集,轮流写出一个大于1的数然后将:“1、所有这个数的倍数;2、这个数的倍数与前面已经删去的数的和”从集合S中删去,现在告诉你S的现状,求所有必胜走法的第一步。

题解:数的数量小于20,可以用位压缩dp,记录S中还剩哪些元素时是否是必胜态,然后通过记忆化搜索求出所有走第一步后是必败态的策略。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 int dp[(1<<20)+2];//1:胜;0:负
 6 int a[25],n;
 7 bool mark[25];
 8 int update(int state,int k)
 9 {
10     int st=state^(1<<k),p=a[k],t;
11     mark[p]=false;
12     for(int i=0;i<n;i++)
13     {
14         if(st&(1<<i))
15         {
16             t=a[i]-p;
17             if(t>1&&!mark[t])
18             {
19                 mark[a[i]]=false;
20                 st^=(1<<i);
21             }
22         }
23     }
24     return st;
25 }
26 void resume(int state,int org)
27 {
28     for(int i=0;i<n;i++)
29     {
30         int t=1<<i;
31         if(!(state&t)&&(org&t))
32             mark[a[i]]=true;
33     }
34 }
35 int dfs(int state)
36 {
37     if(dp[state]!=-1)
38         return dp[state];
39     for(int i=0;i<n;i++)
40     {
41         if(state&(1<<i))
42         {
43             int st=update(state,i);
44             if(dfs(st)==0)
45             {
46                 resume(st,state);
47                 return dp[state]=1;
48             }
49             resume(st,state);
50         }
51     }
52     return dp[state]=0;
53 }
54 int main()
55 {
56     int ca=0;
57     while(scanf("%d",&n),n)
58     {
59         int state=0;
60         memset(mark,false,sizeof(mark));
61         memset(dp,-1,sizeof(dp));
62         dp[0]=0;
63         for(int i=0;i<n;i++)
64             scanf("%d",&a[i]),mark[a[i]]=true,state|=(1<<i);
65         sort(a,a+n);
66         int top=0,ans[25];
67         for(int i=0;i<n;i++)
68         {
69             int st=update(state,i);
70             if(dfs(st)==0)
71                 ans[top++]=a[i];
72             resume(st,state);
73         }
74         printf("Test Case #%d\n",++ca);
75         if(top==0)
76             printf("There's no winning move.\n\n");
77         else
78         {
79             printf("The winning moves are:");
80             for(int i=0;i<top;i++)
81                 printf(" %d",ans[i]);
82             printf("\n\n");
83         }
84     }
85     return 0;
86 }
 

猜你喜欢

转载自blog.csdn.net/wuzhenzi5193/article/details/81590051
今日推荐