题面

题面

题解

通过观察,我们可以发现如下性质:

  • 可以看做是2个人在不断移动空格,只是2个人能移动的边不同
  • 一个位置不会被重复经过 : 根据题目要求,因为是按黑白轮流走,所以不可能重复经过一个点,不然就变成一个人连续走2次了
  • 原图是一个二分图 : 也是由按黑白轮流走这个要求得到的

    因此我们对原图按照与原点的距离进行黑白染色,再跑二分图博弈即可。
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 45
#define ac 5000 int n, m, sx, sy, all;
int id[AC][AC], ans[ac], link[ac];
int a[6] = {-1, 1, 0, 0}, b[6] = {0, 0, -1, 1};
bool can[AC][AC], z[ac], vis[ac];
char s[AC][AC]; struct node{int x, y;}back[ac]; inline int read()
{
int x = 0;char c = getchar();
while(c > '9' || c < '0') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x;
} bool check(int x, int y)//起点是黑色
{
int tmp = abs(x - sx) + abs(y - sy);
if((tmp & 1) && s[x][y] == 'O') return 1;//相距奇数格,则为白格,需要白色
else if(!(tmp & 1) && s[x][y] == 'X') return 1;
else if(s[x][y] == '.') return 1;
return 0;
} bool dfs(int x)
{
for(R i = 0; i < 4; i ++)
{
int xx = back[x].x + a[i], yy = back[x].y + b[i], ID = id[xx][yy];
if(xx <= 0 || yy <= 0 || xx > n || yy > m) continue;
if(!can[xx][yy] || vis[ID]) continue;
vis[ID] = true;
if(!link[ID] || dfs(link[ID]))
{
link[ID] = x, link[x] = ID;
return true;
}
}
return false;
} void cal()
{
int tmp = (sx + sy) % 2;
for(R i = 1; i <= all; i ++)
{
int x = back[i].x, y = back[i].y;
if((x + y) % 2 != tmp || !can[x][y]) continue;//和为奇数则在T集合
memset(vis, 0, sizeof(vis)), dfs(i);
}
} bool dfs1(int x)
{
for(R i = 0; i < 4; i ++)
{
int xx = back[x].x + a[i], yy = back[x].y + b[i], ID = id[xx][yy];
if(xx <= 0 || yy <= 0 || xx > n || yy > m) continue;
if(!can[xx][yy] || vis[ID]) continue;
vis[ID] = true;
if(!link[ID] || dfs(link[ID])) return true;
}
return false;
} void pre()
{
n = read(), m = read(), all = n * m;
int tmp1 = 1, tmp2 = 2;
for(R i = 1; i <= n; i ++)
{
scanf("%s", s[i] + 1);
for(R j = 1; j <= m; j ++)
{
if(s[i][j] == '.') sx = i, sy = j;
if((i + j) & 1) id[i][j] = tmp2, back[tmp2] = (node){i, j}, tmp2 += 2;
else id[i][j] = tmp1, back[tmp1] = (node){i, j}, tmp1 += 2;
}
}
for(R i = 1; i <= n; i ++)
for(R j = 1; j <= m; j ++) can[i][j] = check(i, j);
} void check_()
{
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= m; j ++) printf("%d ", can[i][j]);
printf("\n");
} for(R i = 1; i <= n; i ++)
{
for(R j = 1; j <= m; j ++) printf("%d ", link[id[i][j]]);
printf("\n");
}
} void work()
{
int T = read() << 1, x, y, ID, tmp; bool done;
for(R i = 0; i <= T; i ++)
{
for(R j = 1; j <= all; j ++) z[j] = 0;
if(i) x = read(), y = read(), ID = id[x][y];
else x = sx, y = sy, ID = id[x][y];
can[x][y] = 0;//这个要在一开始就修改
if(!link[ID]) continue;//搜S/T集合中有没有可到达的同侧未匹配点来取代它,因为直接搜不太方便,所以直接搜对面的匹配点是否可以找到增广路
memset(vis, 0, sizeof(vis));
done = dfs(link[ID]);//找到了说明这个点不是必须点
tmp = link[ID];//所以搜这个点的匹配点是否可以找到对面的一个未匹配点(反向增广)
if(done) link[ID] = 0;//清空这个点的匹配,因为这个点已经到过了,所以就不能到达了,如果已经匹配上了就不能改了
else if(!done) link[ID] = link[tmp] = 0, ans[i] = true;//没有可取代点就先手必胜
}
/*for(R i = 0; i <= T; i ++) printf("%d ", ans[i]);
printf("\n");*/
int rnt = 0;
for(R i = 0; i <= T; i += 2)
if(ans[i] == 1 && ans[i + 1] == 1) ++ rnt;
printf("%d\n", rnt);
for(R i = 0; i <= T; i += 2)
if(ans[i] == 1 && ans[i + 1] == 1) printf("%d\n", (i + 2) >> 1);
} int main()
{
// freopen("in.in", "r", stdin);
pre();
cal();
work();
// fclose(stdin);
return 0;
}

[NOI2011]兔兔与蛋蛋游戏 二分图博弈的更多相关文章

  1. [luogu1971 NOI2011] 兔兔与蛋蛋游戏 (二分图博弈)

    传送门 Solution 补一篇二分图博弈 这个博客写的很详细qwq: https://www.cnblogs.com/maijing/p/4703094.html Code //By Menteur ...

  2. BZOJ.2437.[NOI2011]兔兔与蛋蛋游戏(二分图博弈 匈牙利)

    题目链接 首先空格的移动等价于棋子在黑白格交替移动(设起点移向白格就是黑色),且不会走到到起点距离为奇数的黑格.到起点距离为偶数的白格(删掉就行了),且不会重复走一个格子. (然后策略就同上题了,只不 ...

  3. [JSOI2009]游戏 二分图博弈

    题面 题面 题解 二分图博弈的模板题,只要会二分图博弈就可以做了,可以当做板子打. 根据二分图博弈,如果一个点x在某种方案中不属于最大匹配,那么这是一个先手必败点. 因为对方先手,因此我们就是要找这样 ...

  4. BZOJ 1443 游戏(二分图博弈)

    新知识get. 一类博弈问题,基于以下条件: 1.博弈者人数为两人,双方轮流进行决策.2.博弈状态(对应点)可分为两类(状态空间可分为两个集合),对应二分图两边(X集和Y集).任意合法的决策(对应边) ...

  5. luogu4055 游戏 (二分图博弈)

    考虑对非障碍的点黑白染色然后做二分图最大匹配,那么有结论,先手必胜当且仅当不是完美匹配,而且可以放的点是那些可以不匹配的点 从非匹配点开始走,后手只能走到匹配点,于是先手就可以走匹配边.由于不能走走过 ...

  6. [模板] 二分图博弈 && BZOJ2463:[中山市选2009]谁能赢呢?

    二分图博弈 from BZOJ 1443 游戏(二分图博弈) - free-loop - 博客园 定义 1.博弈者人数为两人,双方轮流进行决策. 2.博弈状态(对应点)可分为两类(状态空间可分为两个集 ...

  7. 【BZOJ 2437】 2437: [Noi2011]兔兔与蛋蛋 (博弈+二分图匹配**)

    未经博主同意不得转载 2437: [Noi2011]兔兔与蛋蛋 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 693  Solved: 442 Des ...

  8. bzoj 2437[Noi2011]兔兔与蛋蛋 黑白染色二分图+博弈+匈牙利新姿势

    noi2011 兔兔与蛋蛋 题目大意 直接看原题吧 就是\(n*m\)的格子上有一些白棋和一些黑棋和唯一一个空格 兔兔先手,蛋蛋后手 兔兔要把与空格相邻的其中一个白棋移到空格里 蛋蛋要把与空格相邻的其 ...

  9. BZOJ2437 NOI2011兔兔与蛋蛋(二分图匹配+博弈)

    首先将棋盘黑白染色,不妨令空格处为黑色.那么移动奇数次后空格一定处于白色格子,偶数次后空格一定处于黑色格子.所以若有某个格子的棋子颜色与棋盘颜色不同,这个棋子就是没有用的.并且空格与某棋子交换后,棋子 ...

随机推荐

  1. Mysql:存储过程游标不进循环的原因详解

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客给刚接触存储过程的朋友做个引导作用,目的是解决游标不走循环 很多人发现他的游标,无论是嵌套循环还是单层 ...

  2. SSM-CRUD实战

    前端最容易出现缓存问题,所以以后每次都必须完全在idea加载完后,再在浏览器端多 执行 ctrl+F5 索要最新copy 这样就能拿到最新的改动了,就不会出现各种代码没问题但是功能就是实现不了的问题 ...

  3. Intellij IDEA 2017 通过scala工程运行wordcount

    首先是安装scala插件,可以通过idea内置的自动安装方式进行,也可以手动下载可用的插件包之后再通过idea导入. scala插件安装完成之后,新建scala项目,右侧使用默认的sbt 点击Next ...

  4. new与alloc/init的区别

    alloc:分配内存. init:初始化. new:代替上面两个函数:分配内存,并且初始化. 注意: 1.在实际开发中很少会用到new,一般创建对象时我们一般是 [[className alloc]i ...

  5. T-SQL语句基础

    连接服务器 - 去哪个仓库找目标数据库 - 找仓库中的目标区域查找目标表 - 找货柜找数据(以行为基础单位) - 在货柜上找到目标的物品 基础T-Sql语句1.SQL语句的注释 2.创建数据库crea ...

  6. commons fileupload上传报错

    这个问题困扰我好久了一直没有找到解决方法,先记录下来. 生产环境(简称A)上老是出错,而测试环境(简称B)一切正常. 我们的框架是JAVA语言编写,基于struts1技术总监自己搭的框架,我在stru ...

  7. devpi 快速入门:上传,测试,推送发行版

    安装 devpi 客户端和服务器端 pip install -U devpi 这将安装devpi-client,devpi-server 和 devpi-web 三个Python PyPi包. 初始化 ...

  8. kafka可靠性

    文章转载自: http://blog.csdn.net/u013256816/article/details/71091774

  9. Thunder团队Final周贡献分分配结果

    小组名称:Thunder 项目名称:爱阅app 组长:王航 成员:李传康.翟宇豪.邹双黛.苗威.宋雨.胡佑蓉.杨梓瑞 分配规则 则1:基础分,拿出总分的20%(8分)进行均分,剩下的80%(32分)用 ...

  10. [pascal入门]数组

    一.本节目标 本节我们将要讲述数组.本节目标: 一维数组 二维数组 字符数组 二.一维数组 我们通过一个案例来简单的理解数组.班主任要计算班级里面50个同学数学成绩的平均成绩,道理上讲这是一个比较简单 ...