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

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


Problem Description
大学时光是浪漫的,女生是浪漫的,圣诞更是浪漫的,但是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先走棋,请输出最后的结果。
 

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

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

Sample Input
  
  
2 3 5 3 3 5 6 0
 

Sample Output
  
  
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;
} 







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值