初识博弈【一】(挑战程序)(poj2348,poj2484)

5 篇文章 0 订阅
3 篇文章 0 订阅

看了看《挑战程序设计竞赛》的4.2博弈方便的知识点。

感觉也真是聪明啊……

整理整理,锻炼大脑~


1】Alice和Bob在玩这样一个游戏:给定k个数字a1,a2…ak。一开始,有x个石子,Alice和Bob轮流取石子。每次所取石子的个数一定要在a1~ak中。Alice先取。取走最后一个石子的一方获胜。当双方都采取最优策略时,谁会获胜?题目假定a1~ak中一定有1.


分析题目,有三种情况:

1.没有剩余,也就是只剩下了0个,那么必败

2.对于某个i(1<=i<=k),j-A[i]必败那么j就是必胜(可以从剩下的j中拿去A[i],达到对方的必败状态)

3.对于某个i(1<=i<=k),j-A[i]必胜那么j就是必败(对方可以从剩下的j中拿去A[i])


建立一个win[j]数组,表示轮到玩家拿的时候剩余j时的胜负状态。



#include <cstdio>
#define maxn 105

int X,K,A[maxn]; 
bool win[maxn];
void slove(){
	
	win[0]=false;
	for(int j=1;j<=X;j++){
		//如果对手达到必败,那么必胜
		win[j]=false;
		/*三种都可
		for(int i=0;i<K;i++){	//如果可取的A[i]<=剩余的j,进入判断 
			win[j] |= ( A[i]<=j  && !win[j-A[i]]);
		} 
		
		for(int i=0;i<K&&A[i]<=j;i++){
			win[j] |= !win[j-A[i]] ;
		} 		
		*/
		for(int i=0;i<K&&A[i]<=j;i++){
			if(!win[j-A[i]])
				win[j] |=true ;
		} 
	
	}
	if(win[X]) puts("Alice");
	else puts("Bob");
}
int main() {
	
	scanf("%d%d",&X,&K);
	for(int i=0;i<K;i++){
		scanf("%d",&A[i]);
	}
	slove();
	
	return 0; 
}





2】POJ2484

A Funny Game
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 4824 Accepted: 2997

Description

Alice and Bob decide to play a funny game. At the beginning of the game they pick n(1 <= n <= 10 6) coins in a circle, as Figure 1 shows. A move consists in removing one or two adjacent coins, leaving all other coins untouched. At least one coin must be removed. Players alternate moves with Alice starting. The player that removes the last coin wins. (The last player to move wins. If you can't move, you lose.) 
 
Figure 1

Note: For n > 3, we use c1, c2, ..., cn to denote the coins clockwise and if Alice remove c2, then c1 and c3 are NOT adjacent! (Because there is an empty place between c1 and c3.) 

Suppose that both Alice and Bob do their best in the game. 
You are to write a program to determine who will finally win the game.

Input

There are several test cases. Each test case has only one line, which contains a positive integer n (1 <= n <= 10 6). There are no blank lines between cases. A line with a single 0 terminates the input. 

Output

For each test case, if Alice win the game,output "Alice", otherwise output "Bob". 

Sample Input

1
2
3
0

Sample Output

Alice
Alice
Bob


n枚硬币排成一个圈,

Alice和Bob轮流从中取1~2枚硬币,取得2枚硬币要相连,取走最后一枚硬币获胜。双方采取最优策略,谁会获胜?


如果两个人取硬币的的状态一样(中间不连续),则是一种必败状态。

A取硬币,B取可以达到 和A同样状态的 硬币,那么B必胜。


所以,Alice在第一步取了1枚或者2枚硬币之后,原本成圈的硬币编程了长度为n-1或者n-2的链,

只要B在中间位置根据奇偶性取走硬币就可以把硬币扽成长度相同的链。

然后A就必败了…

当然除了N<=2的情况。

好吧,思维绕一点,但是想清楚了,代码一下就出来…所以这种题考的实际就是智商…多做多看~…

#incldue <cstdio>

int main(){
	int n;
	scanf("%d",&n);
	if(n<+2) puts("Alice");
	else puts("Bob");
	return 0;
}




3.Poj2348

Euclid's Game
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 8594 Accepted: 3500

Description

Two players, Stan and Ollie, play, starting with two natural numbers. Stan, the first player, subtracts any positive multiple of the lesser of the two numbers from the greater of the two numbers, provided that the resulting number must be nonnegative. Then Ollie, the second player, does the same with the two resulting numbers, then Stan, etc., alternately, until one player is able to subtract a multiple of the lesser number from the greater to reach 0, and thereby wins. For example, the players may start with (25,7): 
         25 7

         11 7

          4 7

          4 3

          1 3

          1 0

an Stan wins.

Input

The input consists of a number of lines. Each line contains two positive integers giving the starting two numbers of the game. Stan always starts.

Output

For each line of input, output one line saying either Stan wins or Ollie wins assuming that both of them play perfectly. The last line of input contains two zeroes and should not be processed.

Sample Input

34 12
15 24
0 0

Sample Output

Stan wins
Ollie wins


辗转相除博弈游戏


预处理:

1.先调整使得a<b

2.若b%a==0 必胜

判断:

1】.b-a<a:只有一种选择,就是减去一个a。

若减去之后为必胜,则自己必败。

若减去之后为必败,则自己必胜。


2】.b-a>a:多种选择,

假设x是使得b-x*a<a的整数,如果从b-(x-1)*a之后,也就达到了状态1 。

2.1如果减去之后是必败态:

则当前状态是必胜态

----------

2.2如果减去之后是必胜态,此时可以减去a*x,这样就达到了2.1所说的必胜态的下一个状态,也就是必败态

所以当前状态是必胜态

---------

Eg:

(4,17)如果17-12=5也就是(4, 5)必败,所以直接-12就能必胜

(4,19)如果19-12=7也就是(4,7),对方必胜,那么直接减去16达到(4,7)对的下一个(4,3)必败状态给对手

也就扭转了局面。达到必胜态

所以,从初始状态开始,首先达到自由度的2状态的一方获胜。


注意这里循环中每次的first状态发生变化

因为每种状态都是互推的,这次的必胜,下次的必败。

所以当遇到可以停止的时候break;



#include <cstdio>

void swap(int &x,int &y){
	int t;
	t=x,x=y,y=t; 
}
int main(){
	int a,b;
	while(scanf("%d%d",&a,&b)!=EOF){
		if(a==0&&b==0)	break;
		bool first=true;
		while(true){
			if(a>b) swap(a,b);
			//第一种情况,b是a的倍数。必胜。 
			if( b%a ==0 ) break;
			
			//第二种情况,必胜。 
			if( b-a > a ) break;
			
			b-=a;
			first=!first;	
		}
		if(first)	puts("Stan wins"); 
		else 	puts("Ollie wins");	
	}
	
	return 0;
}



















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值