HDU 4678 Mine (博弈SG+自由度原理)

2024-04-16 11:08

本文主要是介绍HDU 4678 Mine (博弈SG+自由度原理),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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
2013 Multi-University Training Contest 8
不懂博弈的话,这题很难做~
题意:
给出一个N*M的格子图,给出K个雷的坐标,模拟扫雷游戏,当翻开空白格子是,它周围的格子会翻开(除了有雷的格子)
当翻开数字格子则显示数字,两个人轮流翻,最后没有格子可以翻的人败
分析:
首先,理解一下自由度原理。( POJ 2348 Euclid's Game,这个题就初步用到了自由度的原理)
在博弈的过程中可能会遇到很多局面,有的局面有够做出多种性质不同的选择,而有的局面只能做出同种性质的选择。
在博弈过程中,当我们走到没有自由度的局面,基本就只能按一个模式走下去了。
比如说这题,当我们将所有的空白点都翻完之后,(也就是只剩下数字点可选的局面),那么胜负已经确定了
因为面对这样的局面,游戏就变成你翻一个数字点我翻一个数字点的模拟。
在博弈里面,游戏双方为了选择最优策略,一定是先选择有自由度的空白点去翻,直到将所有的空白点翻完。
也就是在求SG值的异或和的时候,必须按照先空白点后数字点去求异或和
其次,分析一个局面的SG值。
懂博弈的自然知道,当前局面的SG值是所有格子的异或和(不懂的可参看挑程316面或者查阅其他资料)
所以分析整个棋盘的SG值就是要求每一个点的SG值
(sg在挑程上的定义: 除 任意一步所能转移到的子局面的SG值以外 最小非负整数
首先最简单的是有雷的点,这样的点显然是必败点,sg = 0
而由于求异或和的时候,0在异或中是不起作用的(即a^0 = a),故而可以不管雷的点
然后分析数字点,这里是指“未翻开状态的数字点”,它的子状态是“已经被翻开的数字点”,子状态的sg = 0,
故而“未翻开的数字点”的sg = 除了0(它的子状态的sg值)以外的最小非负整数1
最后是空白点,首先要明确的一点是,随着这个空白点翻开的有数字点有空白点,但是它的sg是与随他翻开的空白的无关
而仅与随他翻开的数字点有关的,为什么,因为在这一片的空白点中,你随便翻哪一个都能导致同样的局面,所以我们只算其中
一个空白点的SG,很显然,相同的数异或和是为0的(即a^a = 0),所以随这个空白点被翻开的数字点的异或和要么为0,要么为1
当周围的数字是奇数个时,异或和为1,那么这个空白点的sg = 除了0和1(子状态的sg)之外的2,
当周围的数字是偶数个时,异或和为0,那么这个空白点的sg = 除了0(子状态的sg)之外的1
然后结合之前所说的自由度原理,此题只需按照空白点,数字点的顺序求SG异或和即可
至于找到空白点周围的数字点的个数,简单bfs就可以了
#define mem(a,x) memset(a,x,sizeof(a))
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int N = 1007; 
bool mine[N][N];
bool vis[N][N];
const int dx[] = {0,0,1,1,1,-1,-1,-1};
const int dy[] = {-1,1,1,-1,0,1,-1,0};
struct Node 
{int x,y;
};
int n,m;
bool ok(int x,int y)
{return x>=0&&y>=0&&x<n&&y<m;
}
bool check(int x,int y)//判断这个点是不是数字点(周围有没有雷)
{for (int i = 0;i < 8;++i){int xx = x + dx[i];int yy = y + dy[i];if (ok(xx,yy)&&mine[xx][yy]) return 1;}return 0;
}
int bfs(int sx,int sy)//返回这个空白点周围的数字点的个数 
{queue<Node>q;Node h;h.x = sx,h.y = sy;int t = 0;vis[sx][sy] = 1;q.push(h);while (!q.empty()){h = q.front();q.pop();if (check(h.x,h.y))//这个点是数字点{++t;continue;} for (int i = 0;i < 8;++i){Node nx = h;nx.x += dx[i];nx.y += dy[i];if (ok(nx.x,nx.y)){if (vis[nx.x][nx.y]) continue;if (mine[nx.x][nx.y]) continue;q.push(nx);vis[nx.x][nx.y] = 1;}}}return t;
}
int main()
{int T,kas = 0;scanf("%d",&T);while (T--){int k;scanf("%d%d%d",&n,&m,&k);mem(mine,0);mem(vis,0);for (int i = 0,x,y;i < k;++i){scanf("%d%d",&x,&y);mine[x][y] = 1;}int s = 0; for (int i = 0;i < n;++i) //选择所有的空白点去翻 {for (int j = 0;j < m;++j){if (!vis[i][j]&&!mine[i][j]&&!check(i,j)){if (bfs(i,j)&1)//奇数个 sg = 2{s ^= 2;} else           //偶数个 sg = 1 {s ^= 1; }}}}for (int i = 0;i < n;++i)  //直到所有空白点翻完,选择数字点(其实这里直接判断剩下的数字点的个数也可以) {for (int j = 0;j < m;++j){if (!vis[i][j]&&!mine[i][j]&&check(i,j)){s ^= 1;}}}printf("Case #%d: ",++kas);if (s) puts("Xiemao"); //非0 即 胜态 else puts("Fanglaoshi");}return 0;
}  


这篇关于HDU 4678 Mine (博弈SG+自由度原理)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/908626

相关文章

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

poj2505(典型博弈)

题意:n = 1,输入一个k,每一次n可以乘以[2,9]中的任何一个数字,两个玩家轮流操作,谁先使得n >= k就胜出 这道题目感觉还不错,自己做了好久都没做出来,然后看了解题才理解的。 解题思路:能进入必败态的状态时必胜态,只能到达胜态的状态为必败态,当n >= K是必败态,[ceil(k/9.0),k-1]是必胜态, [ceil(ceil(k/9.0)/2.0),ceil(k/9.

hdu3389(阶梯博弈变形)

题意:有n个盒子,编号1----n,每个盒子内有一些小球(可以为空),选择一个盒子A,将A中的若干个球移到B中,满足条件B  < A;(A+B)%2=1;(A+B)%3=0 这是阶梯博弈的变形。 先介绍下阶梯博弈: 在一个阶梯有若干层,每层上放着一些小球,两名选手轮流选择一层上的若干(不能为0)小球从上往下移动,最后一次移动的胜出(最终状态小球都在地面上) 如上图所示,小球数目依次为

hdu4407(容斥原理)

题意:给一串数字1,2,......n,两个操作:1、修改第k个数字,2、查询区间[l,r]中与n互质的数之和。 解题思路:咱一看,像线段树,但是如果用线段树做,那么每个区间一定要记录所有的素因子,这样会超内存。然后我就做不来了。后来看了题解,原来是用容斥原理来做的。还记得这道题目吗?求区间[1,r]中与p互质的数的个数,如果不会的话就先去做那题吧。现在这题是求区间[l,r]中与n互质的数的和

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

hdu 2093 考试排名(sscanf)

模拟题。 直接从教程里拉解析。 因为表格里的数据格式不统一。有时候有"()",有时候又没有。而它也不会给我们提示。 这种情况下,就只能它它们统一看作字符串来处理了。现在就请出我们的主角sscanf()! sscanf 语法: #include int sscanf( const char *buffer, const char *format, ... ); 函数sscanf()和

hdu 2602 and poj 3624(01背包)

01背包的模板题。 hdu2602代码: #include<stdio.h>#include<string.h>const int MaxN = 1001;int max(int a, int b){return a > b ? a : b;}int w[MaxN];int v[MaxN];int dp[MaxN];int main(){int T;int N, V;s

hdu 1754 I Hate It(线段树,单点更新,区间最值)

题意是求一个线段中的最大数。 线段树的模板题,试用了一下交大的模板。效率有点略低。 代码: #include <stdio.h>#include <string.h>#define TREE_SIZE (1 << (20))//const int TREE_SIZE = 200000 + 10;int max(int a, int b){return a > b ? a :