您的位置:首页 > 其它

初始博弈【二】Nim(hdu 1849,poj1704)

2016-05-20 13:25 411 查看
Nim                                                           

有n堆石子,每堆有ai颗石子,Alice和Bob轮流从非空的石子堆中取走至少一颗石子。Alice先取,去逛所有石子的一方获胜。当双方都采取最优策略时,谁会获胜?

1<=n<=1^6

1<=ai<=10^9

INPUT:

3

1 2 4

OUTPUT:

Alice

注意这个结论成立:

a1 XOR a2 XOR a3 XOR ……XOR an ≠ 0  ==> 必胜态

a1 XOR a2 XOR a3 XOR ……XOR an = 0  ==> 必败态

 

所以呢,非0则Alice获胜,为0则Bob获胜

《挑战程序》上的证明如下:

一旦从XOR为0的状态取走至少一颗石子,XOR就一定会变成非0。因此,可以证实必败之后肯定是必胜。

--------------------

观察XOR的二进制表示最高位的1,选取石子数的二进制表示对应位也为1的某堆石子。

只要从中取走使得该位变为0,且其余XOR中的1也反转的数量的石子,XOR就可以变成0。

同时,看了看这几篇博文感觉更加详细
http://blog.csdn.net/lgdblue/article/details/15809893 http://blog.csdn.net/acm_cxlove/article/details/7854530
第一个博客中的例子就很好理解^_^

核心代码:

int N;

void solve(){
int x=0;
for(int i=0;i<N;i++) x^A[i];

if(x!=0) puts("Alice");
else puts("Bob");
}


hduoj1849

Rabbit and Grass

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 3350    Accepted Submission(s): 2496


[align=left]Problem Description[/align]
大学时光是浪漫的,女生是浪漫的,圣诞更是浪漫的,但是Rabbit和Grass这两个大学女生在今年的圣诞节却表现得一点都不浪漫:不去逛商场,不去逛公园,不去和AC男约会,两个人竟然猫在寝食下棋……

说是下棋,其实只是一个简单的小游戏而已,游戏的规则是这样的:

1、棋盘包含1*n个方格,方格从左到右分别编号为0,1,2,…,n-1;

2、m个棋子放在棋盘的方格上,方格可以为空,也可以放多于一个的棋子;

3、双方轮流走棋;

4、每一步可以选择任意一个棋子向左移动到任意的位置(可以多个棋子位于同一个方格),当然,任何棋子不能超出棋盘边界;

5、如果所有的棋子都位于最左边(即编号为0的位置),则游戏结束,并且规定最后走棋的一方为胜者。

对于本题,你不需要考虑n的大小(我们可以假设在初始状态,棋子总是位于棋盘的适当位置)。下面的示意图即为一个1*15的棋盘,共有6个棋子,其中,编号8的位置有两个棋子。



大家知道,虽然偶尔不够浪漫,但是Rabbit和Grass都是冰雪聪明的女生,如果每次都是Rabbit先走棋,请输出最后的结果。
 

[align=left]Input[/align]
输入数据包含多组测试用例,每个测试用例占二行,首先一行包含一个整数m(0<=m<=1000),表示本测试用例的棋子数目,紧跟着的一行包含m个整数Ki(i=1…m; 0<=Ki<=1000),分别表示m个棋子初始的位置,m=0则结束输入。

 

[align=left]Output[/align]
如果Rabbit能赢的话,请输出“Rabbit Win!”,否则请输出“Grass Win!”,每个实例的输出占一行。

 

[align=left]Sample Input[/align]

2
3 5
3
3 5 6
0

 

[align=left]Sample Output[/align]

Rabbit Win!
Grass Win!

 

#include <cstdio>

int main(){
int n;

while(scanf("%d",&n)!=EOF){
if(n==0) break;
int ans=0,x;
for(int i=0;i<n;i++){
scanf("%d",&x);
ans^=x;
}
if(ans==0) puts("Grass Win!");
else puts("Rabbit Win!");
}

return 0;
}


POJ1704

Georgia and Bob

Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 9007 Accepted: 2899
Description

Georgia and Bob decide to play a self-invented game. They draw a row of grids on paper, number the grids from left to right by 1, 2, 3, ..., and place N chessmen on different grids, as shown in the following figure for example: 



Georgia and Bob move the chessmen in turn. Every time a player will choose a chessman, and move it to the left without going over any other chessmen or across the left edge. The player can freely choose number of steps the chessman moves, with the constraint
that the chessman must be moved at least ONE step and one grid can at most contains ONE single chessman. The player who cannot make a move loses the game. 

Georgia always plays first since "Lady first". Suppose that Georgia and Bob both do their best in the game, i.e., if one of them knows a way to win the game, he or she will be able to carry it out. 

Given the initial positions of the n chessmen, can you predict who will finally win the game? 

Input

The first line of the input contains a single integer T (1 <= T <= 20), the number of test cases. Then T cases follow. Each test case contains two lines. The first line consists of one integer N (1 <= N <= 1000), indicating the number of chessmen. The second
line contains N different integers P1, P2 ... Pn (1 <= Pi <= 10000), which are the initial positions of the n chessmen.
Output

For each test case, prints a single line, "Georgia will win", if Georgia will win the game; "Bob will win", if Bob will win the game; otherwise 'Not sure'.
Sample Input
2
3
1 2 3
8
1 5 6 7 9 12 14 17

Sample Output
Bob will win
Georgia will win


棋盘游戏~

将棋子两两整体考虑,然后就可以转化成Nim啦~

【1】如果为偶数个棋子的话:两两之间的间隔作为每堆石子的个数。

          将俩个里面右边的棋子左移->取石子。

          将俩个里面左边的棋子左移.距离变大,石子增多,这里不同于Nim,但是再将右边的棋子左移就又变成Nim了,所以也不影响~

          这样呢,所有的棋子之间的间隔变成0也就是取完了石子,达到必胜态。

          间隔为0-->不管前面的棋子怎么动,只要挪动跟他成对的后面的那个棋子到相邻位置就好了。

---------------

【2】如果为奇数个棋子。设置一个坐标为0的就好了~

#include <cstdio>
#include <algorithm>
#define maxn 10005
using namespace std;
int P[maxn],n;

void solve(){
if(n%2!=0){	//奇数
P[n++]=0;
}
sort(P,P+n);
int ans=0;
for(int i=1;i<n;i+=2){
ans^=(P[i]-P[i-1]-1);
}
if(ans==0) puts("Bob will win");
else puts("Georgia will win");

}

int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&P[i]);
}
solve();

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: