POJ1143 Number Game(DP)

题目大意:

就是说两个人交换选一些数,如果a,b被选过了,那么k*a+m*b(k,m >=0 )这样的数就不能再被选择,现在给你一些还没有选的数,问选哪个数可以使你必胜

如样例:

2 5

如果你选2,由于3已经选过了,而2+3=5,所以5也不能备选择。所以选2就为必胜的选择

我的思路:

,这道题的最初要想到的就是,由于题目的给的数的范围很小,<=20。所以表示这些数的集合就可以用二进制模拟。

用一个DP数组就可以存下,他有两个值就是0和1,表示必胜和必输两个状态。详见代码:

 

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 #define MAX(a,b) (a) > (b)? (a):(b)
 6 #define MIN(a,b) (a) < (b)? (a):(b)
 7 #define mem(a) memset(a,0,sizeof(a))
 8 #define INF 1000000007
 9 #define MAXN 1<<20
10 #define MACN 20
11 
12 #define JUDGE (((1<<(ma[j]-ma[i]-1)) & ~st) &&(ma[j]-ma[i] != 1)) || (!((ma[j]+1)%(ma[i]+1)))
13 
14 using namespace std;
15 
16 int DP[MAXN],ma[MACN],vis[MAXN];
17 int N;
18 
19 int  search(int k,int state)
20 {
21     if(vis[state])return DP[state];
22     vis[state]=1;
23     if(state == 0)return 0;
24     if(k == 1)return DP[state] = 1;//集合里面只有一个数了,一定是必胜状态
25     int i, j, key=0;
26     for(i = 0;i < N;i ++ )
27     {
28         int st = state;
29         if((1<<ma[i]) & state)
30         {
31             for(j = i+1; j < N; j ++ )//首先去掉ma[i]的倍数和(ma[j]-ma[i])已经使用了的ma[j]
32             {
33                 if( ((1<<ma[j]) & st) && (JUDGE) )
34                 {
35                     st ^= (1<<ma[j]);
36                 }
37             }
38             key = search(k-1, st^(1<<ma[i]));
39             if( !key )return DP[state]=1;//一旦下一个状态有必输的状态,那这个状态就是必胜的
40         }
41     }
42     return DP[state]=0;
43 }
44 
45 int main()
46 {
47     int cas=1;
48     while(~scanf("%d",&N) && N)
49     {
50         mem(vis);
51         int i,j,state=0;
52         int ans[MACN]={0},count=0;
53 
54         for(i=0;i<N;i++)
55         {
56             scanf("%d",&ma[i]);
57             ma[i]--;
58             state ^= (1<<ma[i]);//初始化状态集合state
59         }
60 
61         sort(ma,ma+N);
62         for(i = 0; i < N; i ++ )
63         {
64             int st = state;
65             for(j = i+1; j < N; j ++ )
66             {
67                 if(JUDGE) st ^= (1<<ma[j]);
68             }
69             if(search(N-1, (1<<ma[i])^st) == 0)
70             {
71                 ans[count++] = ma[i]+1;
72             }
73         }
74 
75         printf("Test Case #%d\n", cas++);
76         if(!count)printf("There's no winning move.\n\n");
77         else {
78             printf("The winning moves are:");
79             for(i=0;i<count;i++)
80                 printf(" %d", ans[i]);
81             printf("\n\n");
82         }
83     }
84     return 0;
85 }

 

转载于:https://www.cnblogs.com/gj-Acit/archive/2013/06/05/3118977.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值