标签:acm算法


2 3 3 0 3 3 1 1 1
Case #1: Xiemao Case #2: Fanglaoshi
题意:
扫雷游戏的博弈,谁先扫完谁赢。扫雷有个明显的规则就是数字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;
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:acm算法
原文地址:http://blog.csdn.net/sky_miange/article/details/47748037