ZOJ 1039 Number Game 记忆化搜索+二进制状态压缩

原创 2015年07月10日 10:51:17

Number Game

Time Limit: 10 Seconds      Memory Limit: 32768 KB

Background

Christiane and Matthias are playing a new game, the Number Game. The rules of the Number Game are:

Christian and Matthias take turns in choosing integer numbers greater than or equal to 2. The following rules restrict the set of numbers which may be chosen:

R1 A number which has already been chosen by one of the players or a multiple of such a number cannot be chosen. (A number z is a multiple of a number y if z can be written as y * x and x is a positive integer.)

R2 A sum of two such multiples cannot be chosen either.

R3 For simplicity, a number which is greater than 20 cannot be chosen either. This enables a lot more NPCs (Non-Personal-Computers) to play this game.

The player who cannot choose any number anymore looses the Number Game.

Here is an example: Matthias starts by choosing 4. Then Christiane is not allowed to choose 4, 8, 12, etc. Let us assume her move is 3. Now, the numbers 3, 6, 9, etc. are excluded, too; furthermore, numbers like: 7 = 3 + 4, 10 = 2 * 3 + 4, 11 = 3 + 2 * 4, 13 = 3 * 3 + 4, . . . are not available. So, in fact, the only numbers left are 2 and 5. Matthias now says 2. Since 5 = 2 + 3 is now forbidden, too, he wins because there is no number for Christiane's move left.

Your task is to write a program which will help to play the Number Game. In general, i.e., without rule R3, this game may go on forever. However, with rule R3, it is possible to write a program that finds a strategy to win the game.


Problem

Given a game situation (a list of numbers which are not yet forbidden), your program should output all winning moves. A winning move is a move by which the player whose turn it is can force a win no matter what the other player will do. Now we define these terms more formally:

A loosing position is a position in which either

1. all numbers are forbidden, or

2. no winning move exists.

A winning position is a position in which a winning move exists.

A winning move is a move after which the position is a loosing position.


Input

The first line contains the number of scenarios.

The input for each scenario describes a game position. It begins with a line containing the number a, 0 <= a < 20 of numbers which are still available. Next follows a single line with the a numbers still available, separated by single blanks.

You may assume that all game positions in the input could really occur in the Number Game (for example, if 3 is not in the list of numbers available, 6 will not be, either).


Output

The output for each scenario begins with a line containing "Scenario #i:" where i is the number of the scenario starting at 1. In the next line either print "There is no winning move." if this is true for the position of the current scenario, or "The winning moves are: w1 w2 . . . wk." where the wi are all the winning moves, in ascending order, separated by single blanks. The output for each scenario should be followed by a blank line.


Sample Input

2
1
2
2
2 3


Sample Output

Scenario #1:
The winning moves are: 2.

Scenario #2:
There is no winning move.


题意:有2到20这个集合序列,告诉一个n个数字的可选序列,两个人从可选序列中选数字,比如说a,那么a的倍数将不能选,a以及a的倍数与已经被标记的数字的和将也不能选,即两个不能取的数字的和也将不能选。只有19个数,通过状态压缩,用dp[1<<19]来保存集合状态即可。对于每一位,1表示可选,0表示不可选。

dp[i]表示对于i这个数表示的状态集合,起始时都初始化为0.。dp[i]=1时,i表示一个状态集合。对于可选的某个数,对他进行遍历,如果选了这个数以后,他所能到达的所有状态都是必输状态,即选了这个数,对手没有数可选了或者选神马都是输,那就把这个数标记为必胜状态。

#include <stdio.h>
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;

int n;
int a;
int MAX=1<<19;

int win[(1<<19)+10];

int get(int mask,int x)
{
    int ret=mask;
    for(int i=x;i<=20;i+=x)//删除倍数
    {
        ret&=~(1<<(i-2));
    }

    for(int i=2;i<=20;i++)
    {
        if( (ret&(1<<(i-2))))//枚举还存在的数
        {
            for(int j=i-x;j>=2;j-=x)//找是否存在两个非法数和也非法的情况
            {
                if(!(ret&(1<<(j-2))))
                {
                    ret&=~(1<<(i-2));
                    break;
                }
            }
        }
    }

    return ret;
}

int dfs(int mask)
{
    if(win[mask]==0)
    return 0;
    if(win[mask]==1)
    return 1;

    for(int i=2;i<=20;i++)
    {
        if(mask&(1<<(i-2)))
        {
            int tmp=get(mask,i);
            if(!dfs(tmp))//如果后面所有都是必输,那么这一步就是必赢
            {
                win[mask]=1;
                return 1;
            }
        }
    }

    win[mask]=0;
    return 0;
}

int main()
{
    int T;
        int mask=MAX;

     scanf("%d",&T);
    {
        for(int ca=1;ca<=T;ca++)
        {
             memset(win,-1,sizeof win);

    for(int i=0;i<19;i++)
        win[1<<i]=1;

            scanf("%d",&n);

             mask=0;

            for(int i=0;i<n;i++)
            {
                scanf("%d",&a);
                mask|=(1<<(a-2));
            }

           printf("Scenario #%d:\n",ca);

           if(!dfs(mask))//对于整个可选集合进行判断,都是必输,那么就没有必胜局
           {
               printf("There is no winning move.\n\n");
           }
           else
           {
               printf("The winning moves are:");
               for(int i=2;i<=20;i++)
               {
                   if(mask&(1<<(i-2)))
                   {
                       int tmp=get(mask,i);
                       if(!dfs(tmp))//如果之后对方是必输局,则这是必胜选择
                       cout<<" "<<i;
                   }
               }

               puts(".\n");
           }

        }

    }
    return 0;
}








ZOJ 1039 Number Game (状态压缩,记忆化搜索)

转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents           by---cxlove 题目:2-20这19个数字的...
  • ACM_cxlove
  • ACM_cxlove
  • 2012年08月10日 16:50
  • 2780

ZOJ - 1039 Number Game 状态压缩

题目:2-20这19个数字的游戏。每取走一个数之后,这个数的倍数便不能再取,而且某两个取过的数的倍数的和,也不能再取。给出当前可取数字的状态,问当前状态是不是先手必胜状态。如果是,输出取法 思路:利...
  • ACVector
  • ACVector
  • 2017年09月30日 23:14
  • 50

ZOJ 1039 Number Game

记得很久前写过,博弈的题目大同小异,要注意的就是两点: 1、状态的表示 2、状态之间的转换:只要能达到必败态,就是必胜态。反之就是必败态。起点为必败态。 另外,数组作为参数传递时是指针传递。 #inc...
  • Crux_D
  • Crux_D
  • 2009年01月13日 19:01
  • 581

zoj 1039 Number Game

恩,做这道题目是因为有人把它归类到dp题中,而最近在专攻dp。这个叫mask dp。不过和我眼中dp的一般算法不太一样。说明我土了。一般dp会先算最小子问题的答案,然后利用小的资问题往大了算,最终得到...
  • cherry_sun
  • cherry_sun
  • 2012年05月13日 21:10
  • 952

zoj - 1039 Number Game

题意:给你n个数  n个数 在2~19
  • u011026037
  • u011026037
  • 2014年10月13日 19:15
  • 411

zoj 3908 Number Game(zoj 2015年10月月赛F题)

Number Game Time Limit: 2 Seconds      Memory Limit: 65536 KB The bored Bob is playing a number ga...
  • caduca
  • caduca
  • 2015年10月11日 17:41
  • 4582

POJ1143:Number Game(状态压缩)

Description Christine and Matt are playing an exciting game they just invented: the Number Game. ...
  • libin56842
  • libin56842
  • 2015年04月30日 00:20
  • 1643

Number Game(ZOJ3908)

题目意思是给出n个数,每次挑两个数,满足加和小于等于k,然后求出这两个数的积。最多操作m次。 求多次的积的最大的和。 首先先明确,最大的数,乘以满足条件的最大的数必然得到的积最大。比如k=8,我有1,...
  • tinyguyyy
  • tinyguyyy
  • 2016年03月22日 20:01
  • 334

ZOJ 3908 Number Game(乱搞)

The bored Bob is playing a number game. In the beginning, there are n numbers. For each turn, Bob wi...
  • u013582254
  • u013582254
  • 2015年10月11日 21:26
  • 588

ZOJ 1039 Number Game(SG博弈+状压+记忆化搜索)

Background Christiane and Matthias are playing a new game, the Number Game. The rules of the Number...
  • qq_38538733
  • qq_38538733
  • 2017年09月01日 09:48
  • 93
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:ZOJ 1039 Number Game 记忆化搜索+二进制状态压缩
举报原因:
原因补充:

(最多只允许输入30个字)