博弈論題集

NYOJ 23 取石子(一)

     有一堆石子共有n個,A和B輪流取,A先,每次最少取1個,最多取m個,先取完者勝,A,B足夠聰明,問誰先勝?

      比較簡單的巴什博弈,若n%(m+1)!=0,A勝,否則B勝。

NYOJ 833 取石子(七)

    n個石子擺成一圈,A和B輪流取,每次可以從中取一個或相鄰兩個,先取完者勝,A先取,問誰勝?

    若n==1||n==2 則A勝,否則B勝。

NYOJ 161 取石子(四)

    兩堆石子分別n,m(n>=m)個,A和B輪流取,有兩種取法,一是在任意的一堆中取走任意多的石子,最少爲一;二是在兩堆中同時取走相同數量的石子。A先取,先取完者勝,問A是否勝?(勝輸出1,負爲0)

    著名的威佐夫博奕

   結論:若(n-m)*(sqrt(5.0)+1.0)/2.0!=m  ,則A勝,否則負。

#include<iostream>
#include<math.h>
using namespace std;
int main()
{
	int a,b;
	while(cin>>a>>b)
	{
		if(a>b)
		{
			a^=b;
			b^=a;
			a^=b;
		}
        double n=((sqrt(5.0)+1)/2.0);
        
		if((a==(int)((b-a)*n))) 
		cout<<0<<endl;
		else
		cout<<1<<endl;
	}
	return 0;
 } 

 

 

NYOJ 837 Wyothoff Game

    題意同上取石子(四),不過現在要求前n(n<=10W)個必敗態,比如A面對(0,0)必敗,面對(1,2)(3,5)(4,7)也必敗,現在給一個n,求前n個必敗態。

    由上面取石子(四)的題解鏈接可知其第n項爲(n*(sqrt(5.0)+1.0)/2,n*(sqrt(5.0)+1.0)/2+n),由此打一個10W的表即可。

#include<iostream>
#include<math.h>
using namespace std;
int main()
{
	int a[100003];
	int i,j;
	a[0]=0;
	double n=(sqrt(5.0)+1)/2;
	for(i=1;i<100001;i++)
	{
		a[i]=(int)(i*n);
	}
	while(cin>>j)
	{
		for(i=0;i<=j;i++)
		{
			printf("(%d,%d)",a[i],a[i]+i);
		}
		printf("\n");
	}
	return 0;
}

NYOJ 585 取石子(六)

   有n堆石子,每堆石子都有任意個,A和B輪流從取任意堆裏取一定的石子,每次只能從一堆裏至少取一個,A先取,先取完者勝,問誰勝?

   此題爲尼姆博弈

   結論:將n個數異或一遍,若不爲0,則A勝,否則B勝。

#include<iostream>
#include<stdio.h> 
using namespace std;
int main()
{
	int a[1000];
	int n,m,i,j=0;
	cin>>n;
	while(n--)
	{
		int sum=0;
		scanf("%d",&m);
		for(i=0;i<m;i++)
		
	    scanf("%d",&a[i]);
		for(i=0;i<m;i++)
		{
			if(a[i]>1)
			sum++;j^=a[i];
		}
		
		
		if((j==0&&sum==0)||(j!=0&&sum>0))
		cout<<"Yougth"<<endl;
		else
		cout<<"Hrdv"<<endl;
		j=0;
	}
	return 0;
 } 

 

 

NYOJ888取石子(九)

   題意同取石子(六),不過先取完者敗,問誰勝?

   尼姆博弈的變形,統計一下所有數一下大於一的個數,並將所有數字異或一遍,若大於一的個數爲0&&異或之後爲0||大於一的個數大於0&&異或之後不爲零,則A(Yougth)勝,否則B(Hrdv)勝,

   代碼:

#include<iostream>
#include<stdio.h> 
using namespace std;
int main()
{
	int a[1000];
	int n,m,i,j=0;
	cin>>n;
	while(n--)
	{
		int sum=0;
		scanf("%d",&m);
		for(i=0;i<m;i++)
		
	    scanf("%d",&a[i]);
		for(i=0;i<m;i++)
		{
			if(a[i]>1)
			sum++;j^=a[i];
		}
		
		
		if((j==0&&sum==0)||(j!=0&&sum>0))
		cout<<"Yougth"<<endl;
		else
		cout<<"Hrdv"<<endl;
		j=0;
	}
	return 0;
 } 

 

NYOJ135取石子(二)

題意同上上取石子(六),不過限定了每堆石子最多可以取的石子數(最少爲一),問A是勝還是敗?(第一行是一個整數T表示測試數據的組數(T<100)每組測試數據的第一行是一個整數N(1<N<100),表示共有N堆石子,隨後的N行每行表示一堆石子,這N行中每行有兩個數整數m,n表示該堆石子共有m個石子,該堆石子每次最多取n(0<=m,n<=2^31)) 

#include<iostream>
using namespace std;
int main()
{
	int n,m,i,j;
	int a[100][2];
	scanf("%d",&n);
	while(n--)
	{
		int tem=0,d=0;
		scanf("%d",&m);
		for(i=0;i<m;i++)
		{
			scanf("%d %d",&a[i][0],&a[i][1]);
		}
		for(i=0;i<m;i++)
		{
			d=a[i][0]%(a[i][1]+1);
			tem^=d;
		}
		
		if(tem==0)
		printf("Lose\n");
		else
		printf("Win\n");
	}
	
	
	return 0;
}

 

NYOJ358取石子(五)

有一堆石子,A和B輪流從中取一定的石子,但規定:第一次不能取完,至少一個;從第二次開始,每個人取的石子數至少爲1,至多爲對手剛取的石子數的兩倍。A先取,問A是否會勝?斐波那契博弈

   結論:若其對應的石子數目剛好是斐波那契數,則A必敗,否則A必勝。

代碼:

這個代碼nyoj過不了,思想沒錯,但我沒找出來是哪錯了。


#include<stdio.h>

unsigned long long a[120];
int main()
{
	unsigned long long n;
	int i;
	a[0]=0;
	a[1]=1;
	for(i=2;i<120;i++)
	a[i]=a[i-1]+a[i-2];
	while(~scanf("%llu",&n))
	{
		int f=0;
		for(i=1;i<120;i++)
		if(a[i]==n)
		{
			f=1;
			break;
		}
		if(f)
		printf("No\n");
		else
		printf("Yes\n");
	}
	return 0;
 } 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章