HDU 4678 Mine

Problem Description
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
 

Source
 

Recommend
zhuyuanchen520   |   We have carefully selected several similar problems for you:   5395  5394  5393  5390  5389 

 


题意:

扫雷游戏的博弈,谁先扫完谁赢。扫雷有个明显的规则就是数字N周围的八个必有N个雷,如果是空白的话,点击那个空白,从周围八个方向延伸,遇到第一个数字为止,连同数字一起扫掉(不会有地雷)。如果吧不是空白,是单独的数字,则只能扫掉一个。。所以这道题就成了sg博弈。。不管对于单独的数字还是和空白联通一起的数字,sg的值必然为正的,先手肯定是必胜的。对于单独的数字,sg的值显然为1。 对于联通块,sg值为数字个数%2+1。。(可以举个例子,假如单独的数字是一个,联通块的数字是两个,不管你怎么点击,先手是必输的,因为此时sg的值为1^1=0。先手到了必败点。)。

做法就是搜索一下能分成几块,然后sg博弈即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <set>
#include <cmath>
using namespace std;
int map[1002][1002];
int vis[1002][1002];
int n,m;
int dir[8][2]= {{0,1},{0,-1},{1,0},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};
bool check(int x,int y)
{
    if(x<n-1 &&map[x+1][y]) return 1;
    if(x>0 &&map[x-1][y]) return 1;
    if(y<m-1 &&map[x][y+1]) return 1;
    if(y>0 &&map[x][y-1]) return 1;
    if(x<n-1 &&y>0 &&map[x+1][y-1]) return 1;
    if(x>0 &&y>0&&map[x-1][y-1]) return 1;
    if(x<n-1 &&y<m-1 &&map[x+1][y+1]) return 1;
    if(x>0&&y<m-1 &&map[x-1][y+1]) return 1;
    return 0;
}
int dfs(int x,int y)
{
    queue<pair<int,int> >q;
    q.push(make_pair(x,y));
    vis[x][y]=1;
    int tot=0;
    while(!q.empty())
    {
        pair<int,int> now=q.front();
        q.pop();
        int nx=now.first;
        int ny=now.second;
        if(check(nx,ny))
        {
            tot++;
            continue;
        }
        for(int i=0; i<8; i++)
        {
            int fx=nx+dir[i][0];
            int fy=ny+dir[i][1];
            if(fx>=n ||fy>=m ||fx<0 ||fy<0)
                continue;
            if(vis[fx][fy])
                continue;
            if(map[fx][fy])
                continue;
            q.push(make_pair(fx,fy));
            vis[fx][fy]=1;
        }
    }
    return tot;
}
int main()
{
    int t;
    cin>>t;
    int dd=0;
    while(t--)
    {
        int x,y,k;
        int i,j;
        memset(vis,0,sizeof(vis));
        memset(map,0,sizeof(map));
        cin>>n>>m;
        cin>>k;
        while(k--)
        {
            cin>>x>>y;
            map[x][y]=1;
        }
        int ans=0;
        for(i=0; i<n; i++)
            for(j=0; j<m; j++)
            {
                if(!vis[i][j] && !check(i,j) && !map[i][j])//联通块 
                {
                    int res=dfs(i,j)%2+1;
                    ans^=res;
                }
            }
        for(i=0; i<n; i++)
            for(j=0; j<m; j++)
                if(!vis[i][j] && check(i,j) && !map[i][j])//单独的数字。
                    ans^=1;
        cout<<"Case #"<<++dd<<":"<<" ";
        if(ans==0)
            cout<<"Fanglaoshi"<<endl;
        else
            cout<<"Xiemao"<<endl;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值