Something about 博弈~(updating...)

目录


(一)巴什博奕(同余)

        只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。

        如果n=m-1,那么由于一次最多能取m个,那先手无论取多少个,后手一定能一次取完所有物品,故先手必败。因此,如果n=(m+1)r + s,(r为任意自然数,s≤m),那么先手要拿走s个物品,如果后手拿走k(≤m)个物品,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,保持这样的取法,先手必胜。

       总之,要保持给对手留下(m+1)的倍数,最后就能获胜

      变相玩法:两人轮流报数,每次至少报1,最多报10,谁能报到100者胜。

(二)Nim博弈(异或)

    游戏开始有n堆石子,第i堆有ai个石子,两个玩家轮流挑一堆石子,并从中取走若干个,最后不能再取的败。

    定理:Nim博弈先手必胜,当且仅当a1^a2^a3^...^an≠0(扩展内容戳这

(三)威佐夫博弈(黄金分割)

有两堆若干物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,,规定每次至少取一个,多者不限。最后取光者获胜。有两堆石子,数量为a,b.设a中的石子数量少于b中的。当a == (b - a) *(1+√5)/2,此时先手必输

Here


【HDU-2176】取(m堆)石子游戏(Nim博弈)

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4498    Accepted Submission(s): 2698

扫描二维码关注公众号,回复: 3584175 查看本文章

Problem Description

m堆石子,两人轮流取.只能在1堆中取.取完者胜.先取者负输出No.先取者胜输出Yes,然后输出怎样取子.例如5堆 5,7,8,9,10先取者胜,先取者第1次取时可以从有8个的那一堆取走7个剩下1个,也可以从有9个的中那一堆取走9个剩下0个,也可以从有10个的中那一堆取走7个剩下3个.

Input

输入有多组.每组第1行是m,m<=200000. 后面m个非零正整数.m=0退出.

Output

先取者负输出No.先取者胜输出Yes,然后输出先取者第1次取子的所有方法.如果从有a个石子的堆中取若干个后剩下b个后会胜就输出a b.参看Sample Output.

Sample Input

2

45 45

3

3 6 9

5

5 7 8 9 10

0

Sample Output

No

Yes

9 5

Yes

8 1

9 0

10 3

Author

Zhousc

Source

ECJTU 2008 Summer Contest

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=2e5+5;
int a[maxn];
int main()
{
	int m,sum;
	while(~scanf("%d",&m)&&m)
	{
		sum=0;
		for(int i=0;i<m;i++)
		{
			scanf("%d",&a[i]);
			sum^=a[i];
		}
		if(sum==0)
		{
			printf("No\n");
			continue;	
		}
		else 
		{
			printf("Yes\n");
			for(int i=0;i<m;i++)
			{	
				if(a[i]>(sum^a[i]))
					printf("%d %d\n",a[i],sum^a[i]);
			}
		}	
	}
	return 0;
}

【ZCMU-1913】 这是Nim嘛?

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 48  Solved: 23
[Submit][Status][Web Board]

Description

有一天,Hx和Xh两个人在玩Nim游戏,他们觉得Nim游戏真是太简单了,于是就稍微修改下玩法:

        每一次可以从任意一堆中拿走任意个石子,也可以将一堆石子分为两个小堆。先拿完者获胜。

若Hx赢,则输出H,否则输出X;

Input

多组输入,直到输入0结束

输入n(1 ≤ n ≤ 10^6)表示数组S的大小;

之后输入n个数,输入m(1 ≤ m ≤ 2^31 - 1)表示石堆Si的石子数量。

Output

若Hx赢,则输出H,否则输出X;

Sample Input

3

2 2 3

2

3 3

0

Sample Output

H

X

【分析】emmm半做半猜~ 因为均分两份嘛,就看一下 每一堆能否被均分,即是否为偶数,如果是的话,就与x-1异或,不然,就与x+1异或了。

#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
    int n;
    while(~scanf("%d",&n)&&n)
	{
        int sum=0,x;
        for(int i=0;i<n;i++)
		{
            scanf("%d",&x);
            if(x%2==0) sum^=x-1;
            else sum^=x+1;
        }
        if(sum)cout<<"H"<<endl;
        else cout<<"X"<<endl;
    }
    return 0;
}

【zcmu】1918: G.这是个博弈(威佐夫博弈)

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 76  Solved: 46
[Submit][Status][Web Board]

Description

有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到HX先取,假设双方都采取最好的策略,问最后HX是胜者还是败者。

Input

输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,000。

输入为0 0的时候结束。

Output

若HX赢,则输出H,否则输出X;

Sample Input

2 1

8 4

4 7

0 0

Sample Output

X

H

X

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
    int a,b;
    while(~scanf("%d%d",&a,&b)&&a&&b)
	{
     	if(a>b)
            swap(a,b);
        double x=(b-a)*(1+sqrt(5))/2;
        if(a==(int)x)
        	cout<<"X"<<endl;
        else
            cout<<"H"<<endl;
    }
    return 0;
}

2001: Return of the Nim(威佐夫博弈+Nim博弈)

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 18  Solved: 13
[Submit][Status][Web Board]

Description

Sherlock and Watson are playing the following modified version of Nim game:
 

  •   There are n piles of stones denoted as  piles0 ,   piles1 ,...,   pilesn-1 , and n is a prime number;
  •   Sherlock always plays first, and Watson and he move in alternating turns. During each turn, the current player must perform either of the following two kinds of moves:  
    1.  Choose one pile and remove k(k >0) stones from it;
    2.  Remove k stones from all piles, where 1≤k≤the size of the smallest pile. This move becomes unavailable if any pile is empty.
  •   Each player moves optimally, meaning they will not make a move that causes them to lose if there are still any better or winning moves.

Giving  the initial situation of each game, you are required to figure out who will be the winner

Input

The first contains an integer, g, denoting the number of games. The 2×g subsequent lines describe each game over two lines:
1. The first line contains a prime integer, n, denoting the number of piles.
2. The second line contains n space-separated integers describing the respective values of piles0, piles1,..., pilesn-1.

  • 1≤g≤15
  • 2≤n≤30, where n is a prime.
  • 1≤pilesi≤10^5 where 0≤i≤n−1

Output

For each game, print the name of the winner on a new line (i.e., either “Sherlock” or “Watson”)

Sample Input

2

3

2 3 2

2

2 1

Sample Output

Sherlock

Watson

【题意】有两种操作,一种是每堆取k个,但是k不能超过最小堆中的石子个数,另一种是可以从任意一堆中取任意个数的石子,题目保证输入的堆数是素数。

【分析】如果去掉第一种操作就是Nim,如果去掉第二种操作就是威佐夫,所以该题就是Nim+威佐夫啦。只有堆数为2的时候才是威佐夫,直接套公式吧,然后Nim,也就是n>=3的时候,执行第二种操作时,是裸的Nim博弈;执行第一种操作:

假如说现在有三堆,个数分别是15,6,9,然后我们可以发现这已经在Nim的平衡状态了,我们写成二进制更好看一些

1 1 1 1

0 1 1 0

1 0 0 1

我们随便取一个k,假如说就取2,那么已经在Nim平衡状态的这个状态肯定会被破坏,就是不平衡了,单看倒数第二位,前两个数的倒数第二位为0,最后一个数的倒数第二位为1 ,只看倒数第二位就知道三个数的异或和一定不为0,所以不在平衡状态,又因为题目保证了素数(其实这里挺坑的,奇数堆就可以),所以如果已经在平衡状态的话,减k操作和普通的Nim操作一定会破坏平衡状态,如果不在平衡状态的话,普通的Nim操作或者是减k操作一定可以达到一种平衡状态(普通的Nim操作就可以,减k有的时候也可以,比如7,6,5所有堆同时减去4就达到了平衡状态,单把最后一堆减4个也是平衡状态),然后发现减k操作好像对于Nim博弈来说...并没有什么影响,所以这个题的题解就是如果只有两堆,就是裸的威佐夫博弈,如果是大于两堆,就是裸的Nim (来自 bless295 的CSDN 博客 )

【代码】

#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
int a[1005];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        if(n==2)
	{
            if(a[0]<a[1])
                swap(a[0],a[1]);
            if(floor((a[0]-a[1])*((sqrt(5.0)+1.0)/2.0))!=a[1])
                printf("Sherlock\n");
            else
                printf("Watson\n");
        }
        else
	{
            int k=a[0];
            for(int i=1;i<n;i++)
                k^=a[i];
            if(k==0)
                printf("Watson\n");
            else
                printf("Sherlock\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38735931/article/details/82912949
今日推荐