POJ 1143

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

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

View Code
 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 }

你可能感兴趣的:(poj)