【博弈 —— NIM模型】

POJ2234 Matches Game

题意 n n 堆石子,每次任选一堆选取任意个,不能选者输。
思路:经典 N I M NIM 模型,石子个数异或和为 0 0 ,则先手必败,否则先手胜。此处的异或和为 0 0 ,是用归纳法进行证明的,不单只适用于 N I M NIM 问题,还在 S G SG 函数中应用广泛,感兴趣可以自行查阅。
代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
#define LOG3(x1,x2,y1,y2,z1,z2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << " , " << z1 << ": " << z2 << endl;
typedef long long ll;
typedef double db;
const int N = 1e5+100;
const int M = 1e5+100;
const db EPS = 1e-9;
using namespace std;

int n;

int main()
{
	while(~scanf("%d",&n)){
		int tp = 0;
		rep(i,1,n){
			int xx; scanf("%d",&xx);
			tp ^= xx;
		}
		if(tp == 0) printf("No\n");
		else printf("Yes\n");
	}
	return 0;
}

POJ1704 Georgia and Bob

题意:一个一维棋盘,棋盘上有 n n 个棋子,已知每个棋子的初始位置。每次可以任选一个棋子向左推任意格子,但不能跨越其他棋子,不能操作者输。
思路:仔细研究这个游戏,可以发现一个规律,就是只要前一个棋子能移动,那后一个棋子一定可以模仿前一个棋子进行移动。因此可以考虑将相邻两个棋子两两分组。
假如棋子个数为偶数,则 1 2 1、2 为一组, 3 4 3、4 为一组…,如果移动分组中的前一个,则我们移动后一个棋子,完全模仿前一个棋子,因此每组棋子中相隔的步数不变。因此可以将每组棋子看成一个石堆,堆中石子个数为两个棋子间距。因此如果石子个数异或和为 0 0 ,则先手输,其余均胜。
假如棋子个数为奇数,则第一个棋子与棋盘最左端构成一组,仍然可以两两分组,异或和为 0 0 则先手输,其余先手胜。到此,即可完成此题。
反思:本题的重点是如何构造出 N I M NIM 模型,将一个博弈游戏转化为 N I M NIM 问题,常见的入手方向是奇偶分组和两两分组。
代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
#define LOG3(x1,x2,y1,y2,z1,z2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << " , " << z1 << ": " << z2 << endl;
typedef long long ll;
typedef double db;
const int N = 1e5+100;
const int M = 1e5+100;
const db EPS = 1e-9;
using namespace std;

int n,a[N];

int main()
{
	int _; scanf("%d",&_);
	while(_--)
	{
		scanf("%d",&n);
		rep(i,1,n) scanf("%d",&a[i]);
		sort(a+1,a+1+n); a[0] = 0;
		int tp = 0, pos;
		if(n%2 == 0) pos = 1;
		else pos = 0;
		while(pos <= n) tp ^= (a[pos+1]-a[pos]-1), pos = pos+2;
		if(tp == 0) printf("Bob will win\n");
		else printf("Georgia will win\n");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41552508/article/details/89155092