菜鸟学习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. windows任务栏消失

    windows任务栏消失,快捷键打开任务管理器,新建任务explorer.exe

  2. Unity Navigation自动寻路

    NavMesh(导航网格) 是3D游戏世界中主动寻路的一种技术,如果你想让游戏人物能自动绕开障碍物到达目的地.那你就来学习下 Navigation导航技术吧O(∩_∩)O~ 首先创建一个项目创建Pan ...

  3. ASIFormDataRequest 上传图片

    - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typica ...

  4. 页面动态数据的滚动效果——jquery滚动组件(vticker.js)

    <script language="javascript" src="lirms/Test/jquery-1.4.2.js"></script ...

  5. POJ 1300 欧拉通路&欧拉回路

    系统的学习一遍图论!从这篇博客开始! 先介绍一些概念. 无向图: G为连通的无向图,称经过G的每条边一次并且仅一次的路径为欧拉通路. 如果欧拉通路是回路(起点和终点相同),则称此回路为欧拉回路. 具有 ...

  6. 编程算法 - 圆圈中最后剩下的数字(递推公式) 代码(C++)

    圆圈中最后剩下的数字(递推公式) 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 0,1...,n-1这n个数字排成一个圆圈, 从数字0開始 ...

  7. vue 单页面应用实战

    1. 为什么要 SPA? SPA: 就是俗称的单页应用(Single Page Web Application). 在移动端,特别是 hybrid 方式的H5应用中,性能问题一直是痛点. 使用 SPA ...

  8. SQL:deferrable initially deferred

    SQL> create table cust(id number,name varchar2(10));Table created SQL> alter table cust add co ...

  9. mysql免安装版配置与使用方法

    mysql免安装版配置与使用方法      以mysql-noinstall-5.1.6(win32)为例 1>把压缩文件mysql-noinstall-5.1.6-alpha-win32.zi ...

  10. C#中的一种按日期分文件夹的日志写法

    众所周知,日志是调试程序的有效途径,有一个好的日志代码,是一个程序小猿梦寐以求的. 以下是我结合网上资源自己总结的一小段代码,请笑纳: 转载请注明来源: http://www.cnblogs.com/ ...