HDU-4678 Mine(BFS,NIM博弈,SG函数)

                                        Mine HDU - 4678

 

Have you ever played a game in Windows: Mine? 
This game is played on a n*m board, just like the Pic(1) 
 
 
On the board, Under some grids there are mines (represent by a red flag). There are numbers ‘A(i,j)’ on some grids means there’re A(i,j) mines on the 8 grids which shares a corner or a line with gird(i,j). Some grids are blank means there’re no mines on the 8 grids which shares a corner or a line with them. 
At the beginning, all grids are back upward. 
In each turn, Player should choose a back upward grid to click. 
If he clicks a mine, Game over. 
If he clicks a grid with a number on it , the grid turns over. 
If he clicks a blank grid, the grid turns over, then check grids in its 8 directions.If the new grid is a blank gird or a grid with a number,it will be clicked too. 
So If we click the grid with a red point in Pic(1), grids in the area be encompassed with green line will turn over. 
Now Xiemao and Fanglaoshi invent a new mode of playing Mine. They have found out coordinates of all grids with mine in a game.  They also find that in a game there is no grid will turn over twice when click 2 different connected components.(In the Pic(2), grid at (1,1) will turn over twice when player clicks (0,0) and (2,2) , test data will not contain these cases). 
Then, starting from Xiemao, they click the grid in turns. They both use the best strategy. Both of them will not click any grids with mine, and the one who have no grid to click is the loser. 
Now give you the size of board N, M, number of mines K, and positions of every mine X  i,Y  i. Please output who will win.
Input
Multicase 
The first line of the date is an integer T, which is the number of the text cases. (T<=50) 
Then T cases follow, each case starts with 3 integers N, M, K indicates the size of the board and the number of mines.Then goes K lines, the ith line with 2 integer X  i,Y  i means the position of the ith mine. 
1<=N,M<=1000 0<=K<=N*M 0<=X  i<N 0<=Y  i<M
Output
For each case, first you should print "Case #x: ", where x indicates the case number between 1 and T . Then output the winner of the game, either ”Xiemao” or “Fanglaoshi”. (without quotes)
Sample Input
2
3 3 0
3 3 1
1 1
Sample Output
Case #1: Xiemao
Case #2: Fanglaoshi

题意:这道题就是两人轮流进行扫雷,在开始前会告诉你雷的位置,每次都可以选择一个非雷的方块,如果该方块是数字,就将该方块标记,如果该方块是空的,那么它以及它周围连着的空的和这些空的连着的数字全部标记,被标记的方块不能再选了,谁先无法继续选择方块进行该操作谁就输了。


思路:这道题首先要用BFS将所有的空白区域找出来,这些空白区域可以看作是一堆石子,每次可以取一个也可以全部取完,例如题中的图就有三堆石子,分别是8,6,19个,其次那些没有连着空白区域的数字就可以看成是一堆只有一个的石子,然后这道题就变成了NIM博弈,SG函数打表可以找到规律,SG[x]=2-x%2,AC代码如下。


#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <set>
#include <functional>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 1e9 + 5;
const int MAXN = 100005;
const int MOD = 1000000007;
const double eps = 1e-8;
const double PI = acos(-1.0);

char MAP[1005][1005];
bool vis[1005][1005];
int solve;
//*空白   X地雷   n数字
int n, m;
int dx[8] = { 0,1,1,1,0,-1,-1,-1 };
int dy[8] = { 1,1,0,-1,-1,-1,0,1 };

struct point
{
	int x;
	int y;
};

queue<point> que;

void bfs(int x, int y, int tag)
{
	while (!que.empty())
	{
		que.pop();
	}
	point s;
	s.x = x;
	s.y = y;
	que.push(s);
	while (que.size())
	{
		point t = que.front();
		que.pop();
		for (int i = 0; i < 8; i++)
		{
			int nx = t.x + dx[i];
			int ny = t.y + dy[i];
			if (1 <= nx&&nx <= n && 1 <= ny&&ny <= m&&vis[nx][ny] == 0)
			{
				if (MAP[nx][ny] == 'n')
				{
					solve++;
					vis[nx][ny] = 1;
				}
				else if (MAP[nx][ny] == '*')
				{
					s.x = nx;
					s.y = ny;
					que.push(s);
					vis[nx][ny] = 1;
				}
			}
		}
	}
}

void init()
{
	for (int i = 0; i <= n; i++)
	{
		for (int j = 0; j <= m; j++)
		{
			MAP[i][j] = '*';
			vis[i][j] = 0;
		}
	}
}


int main()
{
	int T;
	int d;
	int x, y;
	int tag;
	int Ans;
	scanf("%d", &T);
	for (int CAS = 1; CAS <= T; CAS++)
	{
		Ans = 0;
		tag = 0;
		scanf("%d%d", &n, &m);
		init();
		scanf("%d", &d);
		for (int k = 1; k <= d; k++)
		{
			scanf("%d%d", &x, &y);
			x++;
			y++;
			MAP[x][y] = 'X';
			for (int i = 0; i < 8; i++)
			{
				if (1 <= x + dx[i] && x + dx[i] <= n && 1 <= y + dy[i] && y + dy[i] <= m&&MAP[x + dx[i]][y + dy[i]] != 'X')
					MAP[x + dx[i]][y + dy[i]] = 'n';
			}
		}
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				if (MAP[i][j] == '*'&&vis[i][j] == 0)
				{
					solve = 0;
					bfs(i, j, tag);
					solve++;
					Ans ^= (2 - solve % 2);
				}
			}
		}
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				if (MAP[i][j] == 'n'&&vis[i][j] == 0)
				{
					Ans ^= 1;
				}
			}
		}
		printf("Case #%d: ", CAS);
		if (Ans == 0)
			printf("Fanglaoshi\n");
		else
			printf("Xiemao\n");
	}
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值