菜鸟学习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. 第07讲- Android项目的打包apk

    第07讲Android项目的打包apk 方法一:在工作目录bin文件夹下有一个与项目同名的apk文件 (最懒惰的方式,不推荐,不安全,不利于版本更新,只有在开发模式时使用) 方法二:使用key方式 签 ...

  2. Install Cocos2d-x v3.3 on Ubuntu 14.04 & Ubuntu 14.10(转)

    Install Cocos2d-x v3.3 on Ubuntu 14.04 & Ubuntu 14.10 1 get the source code sudo apt-get install ...

  3. DreamWeaver文件保存时,提示"发生共享违例"问题的解决方法

    在学习牛腩老师的JS视频中,视频中的例子要求实现一个是23个3相乘的结果,在用Dreamweaver制作时,, <script language="javascript" t ...

  4. JavaScript ----------- 组合继承

    继承 实现继承:继承实际的方法.ECMAScript 只支持实现继承,而且其实现基础主要是依靠原型链来实现的. 基本思想是:利用原型来实现一个引用类型继承另外一个引用类型的属性和方法. 原型 - 构造 ...

  5. MongoDB学习笔记03

    限制结果的返回数量可以使用limit.skip sort用一个对象作为参数:一组键/值对,键对应文档的键名,值代表排序的方向(1:升序,-1:降序):如果指定了多个键,则按照多个键的顺序诸个排序. M ...

  6. AFNetWorking 关于manager.requestSerializer.timeoutInterval 不起作用的问题

    之前一直遇到关于AFNetWorking请求时间设置了但是不起作用的情况,现用如下方式设置AF的超市时间即可. [manager.requestSerializer willChangeValueFo ...

  7. Linux脚本中使用特定JDK

    有时linux系统中装了很多应用,我们又不能覆盖系统中设置的版本,此时我们就需要在脚本文件中设置特定版本. export JAVA_HOME= export CLASSPATH=.:$JAVA_HOM ...

  8. C++中的条件传送代码

    条件传送代码-这种代码先计算一个条件操作的两种结果,然后再条件从而选其中一个-条件传送代码匹配了现代处理器的性能特征(因为现代处理器是流水线) void minmax2(int a[],int b[] ...

  9. hdu3998 Sequence(最大流,LIS)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Sequence Time Limit: 2000/1000 MS (Java/O ...

  10. phpexcel导入excel文件报the filename xxx is not recognised as an OLE file错误。

    工作中频繁会用phpexcel类导入excel文件的数据到数据库,目前常用的excel文件格式有:xls.csv.xlsx. 刚开始,针对xls文件,使用如下程序,能正常运行: $objReader ...