8.15练习12 博弈论 巴什博弈/Nim博弈/威佐夫博弈

Brave Game

Good Luck in CET-4 Everybody!

Play a game

Northcott Game

取石子游戏


今天的题真是日了狗了,主要是先做完的人太快了。你知道我刚进教室看见人家大神做完了出来是什么感受么。。

Brave Game

1、 本游戏是一个二人游戏;
2、 有一堆石子一共有n个;
3、 两人轮流进行;
4、 每走一步可以取走1…m个石子;
5、 最先取光石子的一方为胜;
Input
输入数据首先包含一个正整数C(C<=100),表示有C组测试数据。
每组测试数据占一行,包含两个整数n和m(1<=n,m<=1000),n和m的含义见题目描述。
Output
如果先走的人能赢,请输出“first”,否则请输出“second”,每个实例的输出占一行。
Sample Input
2
23 2
4 3
Sample Output
first
second

典型的巴什博弈,n个石子最多取m个,必胜态是m+1的倍数
代码不贴了,,


Good Luck in CET-4 Everybody!

1、 总共n张牌;
2、 双方轮流抓牌;
3、 每人每次抓牌的个数只能是2的幂次(即:1,2,4,8,16…)
4、 抓完牌,胜负结果也出来了:最后抓完牌的人为胜者;
1、 总共n张牌;
2、 双方轮流抓牌;
3、 每人每次抓牌的个数只能是2的幂次(即:1,2,4,8,16…)
4、 抓完牌,胜负结果也出来了:最后抓完牌的人为胜者;
Sample Input
1
3
Sample Output
Kiki
Cici

你看博弈问题每回都得加上说选手的脑子没毛病,算是个标志吧。这个题一开始我就想错了,我把数字转成二进制,有几个1就得拿几次,1的个数是奇数个就是先拿的赢,反之后者赢。真是看大神先出来自己着急坏了,没有认真仔细思考活该WA了。
解法就是分析必胜点和必败点,先找到2的幂数是必胜点,再找到3是必败点,又由3得到一系列能到达3的必胜点,一直往后标记。有点像素数筛法。
代码如下

//You match them
#include<iostream>
#include<cstdio>
using namespace std;
bool positive[3000];
int two[15];
void Initial()
{
	two[0]=1;
	positive[0]=1;
	positive[1]=1;
	for(int i=1;i<=10;i++)
	{
		two[i]=two[i-1]<<1;
		positive[two[i]]=1;
	}
	for(int i=0;i<=1000;i++)
	{
		if(positive[i])
			continue;
		for(int j=0;j<=10;j++)
			positive[i+two[j]]=1;
	}
	return;
}

int main()
{
	int n;
	Initial();
	while(scanf("%d",&n)!=EOF)
	{
		if(positive[n])
			printf("Kiki\n");
		else printf("Cici\n");
	}
	return 0;
	
}

也不难


Play a game

New Year is Coming!
ailyanlu is very happy today! and he is playing a chessboard game with 8600.
The size of the chessboard is nn. A stone is placed in a corner square. They play alternatively with 8600 having the first move. Each time, player is allowed to move the stone to an unvisited neighbor square horizontally or vertically. The one who can’t make a move will lose the game. If both play perfectly, who will win the game?
Input
The input is a sequence of positive integers each in a separate line.
The integers are between 1 and 10000, inclusive,(means 1 <= n <= 10000) indicating the size of the chessboard. The end of the input is indicated by a zero.
Output
Output the winner (“8600” or “ailyanlu”) for each input line except the last zero.
No other characters should be inserted in the output.
Sample Input
2
0
Sample Output
8600
题目大意就是有个n
n的棋盘,从左下角,两人分别移动水平或竖直一步,不能移动到重复的位置,最后移动的人赢。
我这个题想了好久好久,还写了个dfs。后来也没搞明白,就是猜了猜跟奇偶有关系,直接交上去就A了。
代码也不贴了


Northcott Game

Problem Description
  Tom和Jerry正在玩一种Northcott游戏,可是Tom老是输,因此他怀疑这个游戏是不是有某种必胜策略,郁闷的Tom现在向你求救了,你能帮帮他么?
游戏规则是这样的:
  如图所示,游戏在一个n行m列(1 ≤ n ≤ 1000且2 ≤ m ≤ 100)的棋盘上进行,每行有一个黑子(黑方)和一个白子(白方)。执黑的一方先行,每次玩家可以移动己方的任何一枚棋子到同一行的任何一个空格上,当然这过程中不许越过该行的敌方棋子。双方轮流移动,直到某一方无法行动为止,移动最后一步的玩家获胜。Tom总是先下(黑方)。图1是某个初始局面,图二是Tom移动一个棋子后的局面(第一行的黑子左移两步)。

在这里插入图片描述
图1

在这里插入图片描述

图2

Input
  输入数据有多组。每组数据第一行为两个整数n和m,由空格分开。接下来有n行,每行两个数Ti,Ji (1 ≤ Ti, Ji ≤ m)分别表示Tom和Jerry在该行棋子所处的列数。
  注意:各组测试数据之间有不定数量的空行。你必须处理到文件末。
Output
对于每组测试数据输出一行你的结果。如果当前局面下Tom有必胜策略则输出“I WIN!”,否则输出“BAD LUCK!”。
Sample Input
3 6
4 5
1 2
1 2

3 6
4 5
1 3
1 2
Sample Output
BAD LUCK!
I WIN!

题目大意就是猫和老鼠做游戏,每次一个人移动自己方的棋子,能移动到一行的任意位置,但是不能越过对方的棋子。给你初始的棋盘,问谁是必胜的
一开始这个题也没好好想,居然没发现这就是传说中的Nim游戏。把一行中黑子和白子的距离看成石头的个数,当所有棋子都挨在一起时必输,也就是最后拿完石头的赢,跟Nim游戏一模一样

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int main()
{
	int n,m;
	int cnt;
	int t,j;
	int dis[1000+10];
	int temp=0;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		cnt=0;
		for(int i=0;i<n;i++)
		{
			scanf("%d%d",&t,&j);
			dis[i]=max(t-j,j-t)-1;
		}
		temp=dis[0];
		for(int i=1;i<n;i++)
			temp=temp^dis[i];
		if(!temp)
			printf("BAD LUCK!\n");
		else 
			printf("I WIN!\n");
	}
	return 0;
}

取石子游戏

Problem Description
有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。
Input
输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,000。
Output
输出对应也有若干行,每行包含一个数字1或0,如果最后你是胜者,则为1,反之,则为0。
Sample Input
2 1
8 4
4 7
Sample Output
0
1
0
题目大意这就是那什么,什么什么威佐夫博弈,开始老师只教会打表了,一看数据10^9我去他妈的吧
然后各种打表找到了黄金分割1.68,谁知道精度不够屡次WA,后来精确到小数点后数十位就对了。
前一万位打的表

#include<iostream>
#include<cstring>
#include<cmath>
#define MAX 10000+10 
#define Gold  1.6180339887498948482045868343656
using namespace std;
int data[MAX];
int main()
{
	memset(data,0,sizeof(data));
	int t=2;
	data[1]=2;
	data[2]=1;
	for(int i=3;i<10000;i++)
	{
		if(data[i])
			continue;
		
		data[i]=i+t;
		
		if(i+t<MAX)
			data[i+t]=i;	
		t++;
	}
	int a,b;
	while(~scanf("%d%d",&a,&b))
	{
		if(a<10000&&b<10000)
		{
			if(data[a]!=b)
				printf("1\n");
			else printf("0\n");
			continue;
		}
		double big=max(a,b);
		double small=min(a,b);
	//	if(abs(small*Gold-big)<1)
		if(int(abs(small*Gold)+1)==big)
			printf("0\n");
		else printf("1\n"); 
	}
	return 0;
}

写完辽,谢谢你看我的文章,我是个刚入门还很有热情的ACM小傻子,天天在大佬的阴影下生活,尤其是今天,哼!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值