南昌大學航天杯第二屆程序設計競賽校賽網絡同步賽B 取石子(博弈&SG函數模板)

題目鏈接:取石子


鏈接:https://www.nowcoder.com/acm/contest/122/B

時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 32768K,其他語言65536K
64bit IO Format: %lld

題目描述 

現在有兩堆石子,兩個人輪流從中取石子,且每個人每一次只能取1、3或9個石子,取到最後一個石子的人win。
假設先手後手都會選擇最好的方式來取石子,請您判斷先後手的輸贏情況。

輸入描述:

多組輸入
每組一行,一行包括兩個正整數n1和n2(1<=n1<=100,1<=n2<=100),代表了兩堆石子的數目

輸出描述:

如果先手能贏,輸出"win";否則就輸出"lose"。
示例1

輸入

複製
1 1 
1 2

輸出

複製
lose
win

參考文章:點擊打開鏈接

博弈論總結:點擊打開鏈接

1、定義:

(1)只有兩人蔘與。

(2)遊戲局面的狀態集合是有限。

(3)對於同一個局面,兩個遊戲者的可操作集合完全相同

(4)遊戲者輪流進行遊戲。

(5)當無法進行操作時遊戲結束,此時不能進行操作的一方算輸。

(6)無論遊戲如何進行,總可以在有限步數之內結束。

1.可選步數爲1~m的連續整數,直接取模即可,SG(x) = x % (m+1);

2.可選步數爲任意步,SG(x) = x;

3.可選步數爲一系列不連續的數,用GetSG()計算

模板1如下(SG打表):

  1. //f[]:可以取走的石子個數  
  2. //sg[]:0~n的SG函數值  
  3. //hash[]:mex{}  
  4. int f[N],sg[N],hash[N];       
  5. void getSG(int n)  
  6. {  
  7.     int i,j;  
  8.     memset(sg,0,sizeof(sg));  
  9.     for(i=1;i<=n;i++)  
  10.     {  
  11.         memset(hash,0,sizeof(hash));  
  12.         for(j=1;f[j]<=i;j++)  
  13.             hash[sg[i-f[j]]]=1;  
  14.         for(j=0;j<=n;j++)    //求mes{}中未出現的最小的非負整數  
  15.         {  
  16.             if(hash[j]==0)  
  17.             {  
  18.                 sg[i]=j;  
  19.                 break;  
  20.             }  
  21.         }  
  22.     }  
  23. }  

模板2如下(dfs):

  1. int f[105],sg[1005];//f[]爲所要拿取的球數    
  2. int sg_dfs(int x)    
  3. {    
  4.     if(sg[x]!=-1)    
  5.         return sg[x];    
  6.     bool visited[1005];//必須在函數裏面定義,在全局定義會出錯    
  7.     memset(visited,0,sizeof(visited));    
  8.     for(int i=1;i<=30;i++)//i<=f[]的項數    
  9.     {    
  10.         if(x>=f[i])    
  11.             visited[sg_dfs(x-f[i])]=1;    
  12.     }    
  13.     for(int i=0;;i++)    
  14.         if(!visited[i])    
  15.         {    
  16.             sg[x]=i;    
  17.             break;    
  18.         }    
  19.     return sg[x];    
  20. }    
  21. int main()    
  22. {    
  23.         memset(sg,-1,sizeof(sg));//sg[]初始化爲-1    
  24.         sort(f,f+n);//將f[]排列    
  25.         if(sg_dfs(m)^sg_dfs(n)^sg_dfs(p))    
  26.             cout<<1<<endl;    
  27.         else    
  28.             cout<<0<<endl;    
  29.     return 0;    
  30. }    

AC代碼:

#include<stdio.h>
#include<string.h>

int f[5],sg[1010];//f[]爲所要拿取的球數 

int sg_dfs(int x)
{
	if(sg[x]!=-1) return sg[x];
	int book[1010];//必須在函數裏定義,全局定義會出錯 
	memset(book,0,sizeof(book));
	for(int i=1;i<=3;i++)//i<=f[]的項數 
	{
		if(x>=f[i]) book[sg_dfs(x-f[i])]=1;
	}
	for(int i=0;;i++)
	{
		if(book[i]==0)
		{
			sg[x]=i;
			break;
		}
	}
	return sg[x];
}

int main()
{
	memset(sg,-1,sizeof(sg));//sg[]初始化爲-1 
	f[1]=1;
	f[2]=3;
	f[3]=9;
	int n,m;
	while(~scanf("%d%d",&n,&m))
	{
		if(sg_dfs(n)^sg_dfs(m)==0) printf("lose\n");
		else printf("win\n");
	}
	return 0;
}

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