BUPT 大二训练-博弈

比赛网址


HDU 3595 GG and MM


EVERY SG:

在验算的过程中,我们可以发现如果X,Y,X>Y而且X / Y==1,则每次从X中取走Y,这步的选择是固定的,但是当X / Y>=2的情况就不一样了,可以控制步数。

在这个游戏中,由于是Every_SG,我们考虑的是步数,

首先,利用辗转相除法计算最原始的步奏

其次,看谁如果拥有第一个X/Y>=2,便具有优先权,可以控制,将 所有的X/Y>=2控制在自己手中,到了最后一个让自己获胜。以上的策略全部由奇偶来决定,如果在某一步操作的时候,第一个和第二个满足X / Y >=2的点,之间原始步奏的奇偶性,如果是相同的奇偶性那么就不需要改变步数,如果是不同的奇偶性,那么就要将步数加一以实现最优策略,   以此得到最大的步数,判断奇偶。

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>

using namespace std;


template<class T>
inline bool read(T &n)
{
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
//-------------------------------------------------------------------

const int INF=0x3f3f3f3f;
const int MAXN=1010;

int Gcd(int a,int b)
{
    int j=-1;//even   0   odd  1
    int step=0,num=2;
    int f[110]={1,a,b};
    while(f[num])
    {
        f[num+1]=f[num-1]%f[num];
        num++;
    }
    step=num-2;
    for(int i=1;i<num-1;i++)
        if(f[i]>=2*f[i+1])
        {
            if(j>0&&(i&1)!=(j&1))
                step++;
            j=i;
        }
    return step;
}

int main()
{
	int n;
	while(read(n))
	{
		int p,q,ans=0;
		for(int i=0;i<n;i++)
		{
			read(p);read(q);
			if(q>p)
                swap(p,q);
			ans=max(Gcd(p,q),ans);
		}
		if(!(ans&1))
			puts("GG");
		else
			puts("MM");
	}
    return 0;
}



POJ 1704 Georgia and Bob

StairCase博弈:

将之转化为Nim博弈,把两个棋子的距离看成一堆石子,因为如果你把左边的棋子移动任意步数,右边的棋子跟着移动相同步数就会抵消(例 2 3 3 等同于 2),这样就转换成Nim游戏了。注意,如果是奇数个的棋子,则将右边挡板当做棋子辅助运算。

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>

using namespace std;


template<class T>
inline bool read(T &n)
{
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
//-------------------------------------------------------------------

const int MAXN=1200;

int a[MAXN];

int main()
{
	int ans,T,i,n;
	read(T);
	while(T--)
	{
		read(n);
		ans=0;
		for(i=0;i<n;i++)
			read(a[i]);
		sort(a,a+n);
		for(i=n-1;i>=1;i-=2)
			ans^= a[i]-a[i-1]-1;
		if(n&1)
			ans^=a[0]-1;
		if(!ans)
		   puts("Bob will win");
  		else
		   puts("Georgia will win");
	 }
	 return 0;
}



HDU 1730 Northcott Game

将之转化为NIM游戏,将把每行黑白子的初始距离设为每堆石子的初始数量,当然不同的是,这个石子不仅可以取,还可以增加,但是因为这个增加的数量是有界限的(比如,白棋左移3格,黑棋左移3格,他们之间的差是不变的,因此可以认为和最初的状态是一样的,无论如何增加,一定会某一棋子到达边界,导致棋子之间的距离再无法增加)。


#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>

using namespace std;

template<class T>
inline bool read(T &n)
{
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
//-------------------------------------------

int main()
{
	int n,m,sum=0;
	while(read(n)&&read(m))
	{
		sum=0;
		for(int i=0;i<n;i++)
		{
			int x,y;
			read(x);read(y);
			sum^=(int)fabs(x-y)-1;	
		}
		if(sum)
			puts("I WIN!");
		else
			puts("BAD LUCK!");
	}
	return 0;
} 



 POJ 2925 Nim

简单NIM游戏的变形:

记n1^n2^n3..^n[m]=x

显然若x=0,则该局势为奇异局势,必输。

如果把ni变成x^ni,则n1^n2^...^n[i-1]^n[i+1]^...^n[m]^x^ni=0,为奇异局势。显然如果ni>x^ni,如果能ni堆中拿走ni-x^ni张牌,则一定会获胜。

所以只用统计ni中比x^ni大于的个数,结果就是先拿者获胜的种数。


<pre name="code" class="cpp">#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>

using namespace std;


template<class T>
inline bool read(T &n)
{
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
//-------------------------------------------------------------------
int main (){int n,t,a[1111];while(scanf("%d",&n) && n != 0){int temp=0;for(int i=0;i<n;i++){scanf("%d",&t);temp^=t;a[i]=t;}int ans=0;if(temp!=0){for(int i=0;i<n;i++){int k = 0; for(int j=0;j<n;j++) if(i!=j) k^=a[j];//只要能够取到K个,就能够根据对称原理获胜 if(k<=a[i]) ans++;}}printf("%d\n",ans);}return 0;}

 

POJ 1067 取石子游戏

裸Wythoff博弈:

你可以根据公式直接得出答案,也可以根据sg推出答案

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>

using namespace std;


template<class T>
inline bool read(T &n)
{
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
//-------------------------------------------------------------------

int main()
{
	int m,n;
	while(read(m)&&read(n))
	{
		if(m>n)
			swap(m,n);
		int k = n - m;
		int data = floor(k*(1.0+sqrt(5.0))/2);
		puts(data == m ? "0" : "1");
	}
	return 0;
}


HDU 1907 John

裸反NIM游戏:


#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>

using namespace std;


template<class T>
inline bool read(T &n)
{
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
//-------------------------------------------------------------------


int main()
{
	int T,n;
    read(T);
    int ans,a,mi;
    while(T--)
    {
        ans=0;mi=-1;
        read(n);
        for(int i=0;i<n;i++)
        	read(a),ans^=a,mi=max(mi,a);
         if(mi>1)
         	if(ans>0)
                puts("John");
          	else
                puts("Brother");
         else
         	if(!ans)
                puts("John");
         	else
                puts("Brother");
    }
    return 0;
}




HDU 1922 a simple stone game

K倍动态减法游戏:

详见论文http://wenku.baidu.com/view/32782dea81c758f5f61f67a8.html?re=view

#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <climits>
#include <complex>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <bitset>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <ctime>
#include <set>
#include <map>
#include <cmath>

using namespace std;

template<class T>
inline bool read(T &n)
{
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
//------------------------------------------------------------------------

const int MAXN=2000010;

int a[MAXN],b[MAXN];
int n,k,cas=1;

int main()
{
	int T;
	read(T);
	while(T--)
	{
		read(n);read(k);
		int i=0,j=0;
		a[0]=b[0]=1;
		while(a[i]<n)
		{
			i++;
			a[i]=b[i-1]+1;
			while(a[j+1]*k<a[i])
				j++;
			if(a[j]*k<a[i])
				b[i]=b[j]+a[i];
			else
				b[i]=a[i];
		}
		printf("Case %d: ",cas++);
		if(a[i]==n)
			puts("lose");
		else
		{
			int ans;
			while(n)
			{
				if(n>=a[i])
				{
					n-=a[i];
					ans=a[i];
				}
				i--;
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值