多校联合第8场1003Mine

       Mine这题对于了解博弈论SG值的人来说,应该是能愉快的解决。我也是最近才开始学习博弈论,这里贴个地址http://www.cnitblog.com/weiweibbs/category/7163.html,我觉得对新手还是能有比较大的帮助的。回到正题。

      Mine题意大概是对扫雷游戏,给你雷的坐标,两个人轮流点,不能点炸弹,最后谁不能点谁就输了。对于这个问题,可以这样想,点击的若是有数字的,就只能点开那个数字块,如果点了空白的地方,则会打开一片区域,而这些区域的边界都是数字(如果存在的话),所以我们就可以把这个问题抽象到取石子游戏中了,首先我们可以通过BFS将棋盘分为几个区域(对应几堆石子)这样的话,对每堆石子我们可采取的策略就是取1颗或者是全部取走(Nim游戏)。

所以现在就是要推出每堆石子的SG值,最后把SG值异或一下就是,0先手必败,非0先手必胜。


       这里可以推导出SG值的一个规律,石子数为n=0 SG=0,石子数为n=1 SG=1,n=2 SG=2,n=3 SG=1 ,n=4 SG=2........可以知道n为奇数时SG=1,n为非零偶数SG=2,所以在分区时统计出每一块区域的石子个数(这里把空白区域算作1颗石子)就行,下面是我AC的代码,在这里注明,这个代码也是在参考了结题报告和网上大牛们的代码之后写出来的,如有雷同,不胜荣幸。。

#include
#include 
#include 
#include 
#include 
using namespace std;

#define maxn 1010
int dir[8][2]={{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1}};
bool bomb[maxn][maxn],visit[maxn][maxn];
queuexpoint;
queueypoint;
int n,m,k;
//检查i ,j 周围是否有炸弹
bool check (int x,int y)
{
	if(x>0&&bomb[x-1][y]) return true;
	if(x0&&bomb[x][y-1]) return true;
	if(y0&&y>0&&bomb[x-1][y-1]) return true;
	if(x>0&&y0&&bomb[x+1][y-1]) return true;
	if(xn-1||py<0||py>m-1) continue;
			if(!visit[px][py]&&!bomb[px][py])
			{
				xpoint.push(px);
				ypoint.push(py);
				visit[px][py]=1;
			}
		}
	}
	return sum;
	
}
int main()
{
	int cas,ncase,i,j,ans;
	//ofstream out("out.txt",ios::out);
	//ifstream in("data.in",ios::in);
	scanf("%d",&ncase);
	//in>>ncase;
	for(int cas=1;cas<=ncase;cas++)
	{
		scanf("%d%d%d",&n,&m,&k);
		//in>>n>>m>>k;
		memset(visit,0,sizeof(visit));
		memset(bomb,0,sizeof(bomb));
		while(!xpoint.empty()) xpoint.pop();
		while(!ypoint.empty()) ypoint.pop();
		int x,y;
		while(k--)
		{
			scanf("%d%d",&x,&y);
			//in>>x>>y;
			bomb[x][y]=1;//表示此处有炸弹
		}
		ans=0;
		for(i=0;i


你可能感兴趣的:(HDU)