简单博弈论专项练习。

 

其实博弈论并没有特别繁琐和复杂,主要是找必败或必胜策略,然后进行转移和分类讨论。后续继续加题。

1.

poj1082  Calendar Game   

Adam and Eve enter this year’s ACM International Collegiate Programming Contest. Last night, they played the Calendar Game, in celebration of this contest. This game consists of the dates from January 1, 1900 to November 4, 2001, the contest day. The game starts by randomly choosing a date from this interval. Then, the players, Adam and Eve, make moves in their turn with Adam moving first: Adam, Eve, Adam, Eve, etc. There is only one rule for moves and it is simple: from a current date, a player in his/her turn can move either to the next calendar date or the same day of the next month. When the next month does not have the same day, the player moves only to the next calendar date. For example, from December 19, 1924, you can move either to December 20, 1924, the next calendar date, or January 19, 1925, the same day of the next month. From January 31 2001, however, you can move only to February 1, 2001, because February 31, 2001 is invalid. 

A player wins the game when he/she exactly reaches the date of November 4, 2001. If a player moves to a date after November 4, 2001, he/she looses the game. 

Write a program that decides whether, given an initial date, Adam, the first mover, has a winning strategy. 

For this game, you need to identify leap years, where February has 29 days. In the Gregorian calendar, leap years occur in years exactly divisible by four. So, 1993, 1994, and 1995 are not leap years, while 1992 and 1996 are leap years. Additionally, the years ending with 00 are leap years only if they are divisible by 400. So, 1700, 1800, 1900, 2100, and 2200 are not leap years, while 1600, 2000, and 2400 are leap years. 

Input

The input consists of T test cases. The number of test cases (T) is given in the first line of the input. Each test case is written in a line and corresponds to an initial date. The three integers in a line, YYYY MM DD, represent the date of the DD-th day of MM-th month in the year of YYYY. Remember that initial dates are randomly chosen from the interval between January 1, 1900 and November 4, 2001. 

Output

Print exactly one line for each test case. The line should contain the answer "YES" or "NO" to the question of whether Adam has a winning strategy against Eve. Since we have T test cases, your program should output totally T lines of "YES" or "NO". 

Sample Input

3 
2001 11 3 
2001 11 2 
2001 10 3 

Sample Output

YES 
NO 
NO 

题意:给定n个日期,定义两种日期走法:1.走到下一月的这一号,2,走到下一天。1号2号轮流走日子,问一号能否胜利(胜利的条件就是他能走到2001年11月4日)。

思路:能得出2001年11月3日和2001年10月4日必胜,然后2001年10月2号也必胜同年9月30也胜。但9月28不行,因为可以变为10月28。 其实不就是月或日加1,末尾状态是奇数,所以需要判断月和日加和,但是注意到9月30和11月30下一天是加和也是奇数。然后get必胜必败状态。

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#pragma GCC optimize(2)
const int maxx=1e5+18;
const ll INF =1e18+9;
using namespace std;

int main() 
{
	ll n,k,i,j,ans;
    scanf("%lld",&n);
    int nian,yue,ri;
    for(i=1;i<=n;i++)
    {
    	scanf("%d%d%d",&nian,&yue,&ri);
    	ans=0;
    	if((yue+ri)%2==1) ans=1;
    	if(ri==30&&(yue==9||yue==11)) ans=0;
    	if(ans==0) printf("YES\n");
    	else 
    	printf("NO\n");
	}
 
	return 0;
}

2.

poj2348 Euclid's Game 

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

 题意:给定两个数,每次操作使得最大值减去最小值的倍数,然后更新最大值。问谁先操作到最大值是最小值的倍数。

思路:依然是判断必胜或必败状态,如果过程中有最大值比最小值大两倍则此时这个人必胜,因为他可以使之后的操作多一步或不多,所以直接用gcd一次判断次数就行了。

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#pragma GCC optimize(2)
const int maxx=1e5+18;
const ll INF =1e18+9;
using namespace std;
int cishu=0;
void gcd(ll a,ll b)
{
	cishu++;
	if(b>a)
	swap(a,b);
	if(a>2*b) return ;
	if(a%b==0) return ;
	gcd(b,a%b);
}
int main() 
{
	ll n,k,i,m,j,ans;
    while(~scanf("%d%d",&n,&m))
    {
    	if(n==0&&m==0) break;
    	ll a1=max(n,m),a2=min(n,m);
    	cishu=0;
    	gcd(a1,a2);
    	if(a1>=2*a2||a1%a2==0)
    	{
    		printf("Stan wins\n");
		}
    	else if(cishu%2==1)
    	{
    		printf("Stan wins\n");
		}	
		else 
    		printf("Ollie wins\n");
	}
	return 0;
}

乘法博弈: 起始为1,每个人可以选择将这个数乘以(a-b) ,问谁先成到n,奇异态:(b+1+k*a*b,a*b*k*a*b) 这个是2和9的

//#include<bits/stdc++.h> 
#include<stdio.h>
#include<math.h>
const int maxx=1e6+19;
#define ll long long
ll a[maxx],b[maxx];
int main()
{
	ll i,j,m,n,k,sum,ans;
	a[1]=1;
	b[1]=9;
	k=2;
	for(i=2;i<=1000;i++)
	{
		a[i]=b[i-1]+1;
		b[i]=b[i-1]*k;
		if(k==2)
		k=9;
		else 
		k=2; 
	}

	while(~scanf("%lld",&n))
	{
		ll cishu=0;
		for(i=1;;i++)
		{
			if(n>=a[i]&&n<=b[i])
			break;
		}
		if(i%2==1)
		{
			printf("Stan wins.\n");
		}
		else 
		printf("Ollie wins.\n");
		
	}
	
	return 0;
}

  nim 博弈求第一次的方案数。

//#include<bits/stdc++.h> 
#include<stdio.h>
#include<math.h>
const int maxx=1e6+19;
#define ll long long
ll a[maxx];
int main()
{
	ll i,j,m,n,k,sum,ans;
	while(~scanf("%lld",&n))
	{
		if(n==0) break;
		ans=0;
		for(i=1;i<=n;i++) 
		{
			scanf("%lld",&a[i]);
			ans^=a[i];
		}
		if(ans==0) printf("0\n");
		else 
		{
			sum=0;
			for(i=1;i<=n;i++)
			{
				ll x=ans^a[i];
				if(x<a[i]) 
				sum++;
			}
			printf("%lld\n",sum);
		}
	}
	
	return 0;
}

成环的每次拿走一个或相邻的两个,n>=3时后手必胜,小于3先手必胜。

代码没什么可写的。

 

 

n堆石头 ,先手一次拿两次,每次在一堆中选择至少一个拿走,后手拿一次。

 

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include <iostream>
#include<string.h>     
#include<algorithm>
#define ll long long
#include<vector>
#include<set>
using namespace std;
const int maxx=1e6+100;
int main()
{   
   int n,i,j,k,m;
    int t;
    int l,r,x;
    scanf("%d",&t);
    for(j=t;j>=1;j--)
    {
        int sum1=0,sum2=0;
        int a;
        scanf("%d%d",&n,&x); // x=1是先手,x==2是后手。
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a);
            if(a==1) sum1++;
            else sum2++;
        }
      int flag=1;
        if(n%3==0)
        {
            if(sum1==n&&x==1) flag=0;
            if(sum2==1&&x==2) flag=0;
         } 
         else if(n%3==1)
         {
             if(sum2<=1&&x==2) flag=0;
             
         }

         if(flag==1)
         printf("Yes\n");
         else
         printf("No\n");
         
        
    }
    return 0;   
}

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值