菜鸟学习ACM,纪录自己成长过程中的点滴。

学习的路上,与君共勉。

ACM学习-POJ-1143-Number Game

Number Game
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 2914   Accepted: 1162

Description

Christine and Matt are playing an exciting game they just invented: the Number Game. The rules of this game are as follows. 
The players take turns choosing integers greater than 1. First, Christine chooses a number, then Matt chooses a number, then Christine again, and so on. The following rules restrict how new numbers may be chosen by the two players:

  • A number which has already been selected by Christine or Matt, or a multiple of such a number,cannot be chosen.
  • A sum of such multiples cannot be chosen, either.

If a player cannot choose any new number according to these rules, then that player loses the game. 

Here is an example: Christine starts by choosing 4. This prevents Matt from choosing 4, 8, 12, etc.Let's assume that his 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 also not available. So, in fact, the only numbers left are 2 and 5. Christine now selects 2. Since 5=2+3 is now forbidden, she wins because there is no number left for Matt to choose. 

Your task is to write a program which will help play (and win!) the Number Game. Of course, there might be an infinite number of choices for a player, so it may not be easy to find the best move among these possibilities. But after playing for some time, the number of remaining choices becomes finite, and that is the point where your program can help. Given a game position (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 who is about to move can force a win, no matter what the other player will do afterwards. More formally, a winning move can be defined as follows.

  • A winning move is a move after which the game position is a losing position.
  • A winning position is a position in which a winning move exists. A losing position is a position in which no winning move exists.
  • In particular, the position in which all numbers are forbidden is a losing position. (This makes sense since the player who would have to move in that case loses the game.)

Input

The input consists of several test cases. Each test case is given by exactly one line describing one position. 

Each line will start with a number n (1 <= n <= 20), the number of integers which are still available. The remainder of this line contains the list of these numbers a1;...;an(2 <= ai <= 20). 

The positions described in this way will always be positions which can really occur in the actual Number Game. For example, if 3 is not in the list of allowed numbers, 6 is not in the list, either. 

At the end of the input, there will be a line containing only a zero (instead of n); this line should not be processed.

Output

For each test case, your program should output "Test case #m", where m is the number of the test case (starting with 1). Follow this by either "There's no winning move." if this is true for the position described in the input file, or "The winning moves are: w1 w2 ... wk" where the wi are all winning moves in this position, satisfying wi < wi+1 for 1 <= i < k. After this line, output a blank line.

Sample Input

2 2 5
2 2 3
5 2 3 4 5 6
0

Sample Output

Test Case #1
The winning moves are: 2 Test Case #2
There's no winning move. Test Case #3
The winning moves are: 4 5 6

Source

题目要求:

Christine和Matt玩一个游戏.游戏的规则如下:一开始有一列数字(2~20),有的被列出,有的没有列出.从Christine开始,两人轮流划去一个已被列出的数字.每划去一个数字,其他的所有的能被不在这个数列的数字的两两整线性表示的数也自动从数列中退出.到最后,轮到某人而此时数列中没有元素时,这个人就输了.

       规定:winning moveà能将对手置于losing position的决策,而losing positionà不存在任何winning move的序列.

这两个概念都是在两人都play perfectly 的前提下提出的.

题目分析:

这是一道博弈题,既然要判断先选哪个数一定获胜,那么可首先枚举要选的第一个数,删除该数影响到的数。

那么什么数(设为x)会受该数(设为m)影响呢?分析可知,条件是x-m不在当前可选数列中,也就是说x-m已经选过。

而又选了m,那么由题意可知x必定受到影响要删除。

条件已知。那么剩下的就是根据必胜状态和必败状态的定义搜索这棵博弈树。直接搜索超时,已经试过了。

在网上搜了下,都没有注释。于是找了个代码,啃啊啃,终于明白了。

用的是记忆化搜索。将已给序列从小到大排序。如果用1表示该数在序列中,0表示不在,那么就用它们对应的二进制数来表示

当前面临的状态,如果面临的状态相同且前面已经得出,那么直接返回该结果即可。需要用的两个二进制数,一个用来表示状

态,另一个用来表示该状态下剩余的数(其中1表示不在可选序列中,0表示在)。这样做在删除数的时候非常方便。

下面给出AC代码。

#include<stdio.h>
#include<string.h> int dp[1<<20];
int info[21];
int n; // 每组的个数 int solve(int a,int b)
{
int i,j,c,d;
if( a == 0 )
return 0;
if( dp[a] != -1 ) //表明已经判断过了。 直接返回结果
return dp[a];
for( i = 0; i < n; i ++ ){
c = a;
d = b;
if( (1 << i) & c ){ //寻找该状态下可选的数,继续搜索
for( j = 0; j + info[i] < 21; j ++ ){ //标记受该数影响的数
if( (1 << j) & d ){
d = d | (1 << (info[i] + j) );
}
}
for( j = 0; j < n; j ++ ){ //删除受影响的数
if( ( (1 << j ) & c ) && ( (1 << info[j]) & d ) ){
c = c^(1 << j);
}
}
if( !solve(c,d) )
return dp[a] = 1;
}
}
return dp[a] = 0;
} int main()
{
int i, j, k;
int a,b; //a表示状态,初始全为1 b表示序列删除的状况,1表示不在,0表示在
int item; // 总的序列。 0表示存在,1表示不在
int res[21];
int case_ = 1; //记录测试组数
while(scanf("%d",&n) != EOF && n!= 0)
{
item = (1<<22) - 3; //将1添进序列,1始终是可选但又不能选的数。总序列变成 11 1111 1111 1111 1111 1101 0指该序列中0存在。
for( i = 0 ; i < n; i ++ ){
scanf("%d", &info[i]);
item ^= (1 << info[i]); //^异或运算符,位值相同为0,不同为1。将序列中的数在item中标记,相应位置都为0,这样做删除方便
}
for( i = 0; i < n; i ++ ){ //冒泡排序
for( j = 0; j < n - i - 1; j ++ ){
if( info[j] > info[j + 1] ) {
info[j] = info[j] ^ info[j + 1];
info[j + 1] = info[j] ^ info[j + 1];
info[j] = info[j] ^ info[j + 1];
}
}
}
memset(dp,-1,sizeof(dp));
for(k = i = 0; i < n;i ++ ){ //枚举第一个被选的数
a = (1<<n) - 1; //a表示状态,初始全为1
b = item; //b表示序列删除的状况,1表示不在,0表示在
for( j = 0; j + info[i] < 21; j ++ ){
if( (1<<j) & b ){ //如果j不在可选序列,那么j + info[i] 会因info[i]的删除而删除
b = b | ( 1 << (j + info[i]) ); //将该数相应位置置1
}
}
for( j = 0; j < n; j ++ ){ //判断哪个数被删除了
if( (1 << info[j]) & b ){
a = a ^ (1 << j); //将该数删除置为0
}
}
if( !solve(a,b) )
res[k ++] = info[i];
}
printf("Test Case #%d\n",case_ ++);
if( k ) {
printf("The winning moves are:");
for( i = 0; i < k; i ++ ){
printf(" %d",res[i]);
}
puts("");
}
else puts("There's no winning move.");
puts("");
}
return 0;
}

附上几个参考链接  http://happylch21.blog.163.com/blog/static/165639759201162243858792/
http://blog.csdn.net/zhengweihit/article/details/5799427

ACM学习-POJ-1143-Number Game的更多相关文章

  1. ACM学习-POJ-1125-Stockbroker Grapevine

    菜鸟学习ACM,纪录自己成长过程中的点滴. 学习的路上,与君共勉. ACM学习-POJ-1125-Stockbroker Grapevine Stockbroker Grapevine Time Li ...

  2. ACM学习-POJ-1003-Hangover

    菜鸟学习ACM,纪录自己成长过程中的点滴. 学习的路上,与君共勉. ACM学习-POJ-1003-Hangover Hangover Time Limit: 1000MS   Memory Limit ...

  3. ACM学习-POJ-1004-Financial Management

    菜鸟学习ACM,纪录自己成长过程中的点滴. 学习的路上,与君共勉. ACM学习-POJ-1003-Financial Management Financial Management Time Limi ...

  4. Poj 1019 Number Sequence( 数据分析和操作)

    一.题目大意 有这样一个序列包含S1,S2,S3...SK,每一个Si包括整数1到 i.求在这个序列中给定的整数n为下标的数. 例如,前80位为1121231234123451234561234567 ...

  5. acm学习指引

    acm学习心得及书籍推荐   一般要做到50行以内的程序不用调试.100行以内的二分钟内调试成功.acm主要是考算法的,主要时间是花在思考算法上,不是花在写程序与debug上. 下面给个计划练练: 第 ...

  6. ACM学习历程—POJ 3764 The xor-longest Path(xor && 字典树 && 贪心)

    题目链接:http://poj.org/problem?id=3764 题目大意是在树上求一条路径,使得xor和最大. 由于是在树上,所以两个结点之间应有唯一路径. 而xor(u, v) = xor( ...

  7. ACM学习历程——HDU 5014 Number Sequence (贪心)(2014西安网赛)

    Description There is a special number sequence which has n+1 integers. For each number in sequence, ...

  8. ACM学习历程——POJ 1700 Crossing River(贪心)

    Description A group of N people wishes to go across a river with only one boat, which can at most ca ...

  9. ACM学习历程——POJ 2376 Cleaning Shifts(贪心)

    Description Farmer John is assigning some of his N (1 <= N <= 25,000) cows to do some cleaning ...

随机推荐

  1. C++私有构造函数

    一. 类的构造函数一般是public的,但是也可以是private的.构造函数为私有的类有这样的特点: <1>不能实例化:因为实例化时类外部无法访问其内部的私有的构造函数: <2&g ...

  2. paip.输入法编程---智能动态上屏码儿长调整--.txt

    paip.输入法编程---智能动态上屏码儿长调整--.txt 作者Attilax ,  EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csd ...

  3. Android图形合成和显示系统---基于高通MSM8k MDP4平台

    介绍了Android SurfaceFlinger层次以下的图形合成和显示系统,主要基于高通MSM8k MDP4x平台. 做为Android Display专题.SurfaceFlinger的详细介绍 ...

  4. jmock2.5基本教程(转)

    原文:http://www.cnblogs.com/zfc2201/archive/2011/12/30/2307970.html jmock2.5基本教程 目录 第0章 概述 第1章 jmock初体 ...

  5. java与.net比较学习系列(4) 运算符和表达式

    上一篇总结了java的数据类型,得到了冰麟轻武等兄弟的支持,他们提出并补充了非常好的建议,在这里向他们表示感谢.在后面的文章中,我会尽力写得更准确和更完善的,加油! 另外,因为C#是在java之后,也 ...

  6. CDN云主机与传统虚拟主机功能对比

    CDN云主机与传统虚拟主机功能对比 传统的虚拟主机都是单台服务器,一旦机器硬件损坏.IP被封.机房网络故障等,都将导致网站不能访问,严重的情况数据还无法及时取回,即使想换一家服务商也因为没有数据而无能 ...

  7. Apache-rhel5.8环境下编译安装

    Apache安装过程 Step 1:安装包gcc或gcc-c++# yum install gcc#yum install gcc-c++ Step 2:安装包APR和APR-Utilapr-1.4. ...

  8. HTML 表单与输出

    我们先来设置一个简单的表单 <!doctype html><html><head> <meta charset="utf-8"> & ...

  9. php 二维码生成类

    <?php /** * BarcodeQR - Code QR Barcode Image Generator (PNG) * @package BarcodeQR * @category Ba ...

  10. Autofac创建实例的方法总结 【转】

    Autofac创建实例的方法总结   1.InstancePerDependency 对每一个依赖或每一次调用创建一个新的唯一的实例.这也是默认的创建实例的方式. 官方文档解释:Configure t ...