题面

题面

题解

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

  • 可以看做是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. 五、利用EnterpriseFrameWork快速开发基于WebServices的接口

    回<[开源]EnterpriseFrameWork框架系列文章索引> EnterpriseFrameWork框架实例源代码下载: 实例下载 前面几章已完成EnterpriseFrameWo ...

  2. python基本数据类型2

    python_day_4 今日大纲: 1. list(增删改查) 列表可以装大量的数据. 不限制数据类型. 表示方式:[] 方括号中的每一项用逗号隔开 列表和字符串一样.也有索引和切片 常用的功能: ...

  3. Python小白学习之文件内建函数

    文件内建函数: 2018-10-24 23:40:02   简单介绍: open()打开文件 read()读取文件(其实是输入文件里的内容到read函数,类似于get(url),所以下面的图片备注的是 ...

  4. TW实习日记:第八天

    今天早上主要是接着做昨天的微信端网页预览附件,听同事说当打包代码放入服务器上后,就不存在跨域问题了,也就懒得自己写接口了,那么就希望自己能一次过吧...结果写着写着,发现开发文档中关于预览文件的方法, ...

  5. IO模型浅析-阻塞、非阻塞、IO复用、信号驱动、异步IO、同步IO

    最近看到OVS用户态的代码,在接收内核态信息的时候,使用了Epoll多路复用机制,对其十分不解,于是从网上找了一些资料,学习了一下<UNIX网络变成卷1:套接字联网API>这本书对应的章节 ...

  6. 电脑提示‘您需要来自Administration的权限才能对此文件夹进行更改’怎么删除文件

    电脑提示'您需要来自Administration的权限才能对此文件夹进行更改'怎么删除文件 应该怎么做 win7系统需要定期删除一些无用的文件,扩大内存空间,但是在删除文件的时候弹出提示"您 ...

  7. kafka浅谈

    关键词 producer       生产者 broker          缓存代理 consumer     消费者 partition       分区 topic            主题 ...

  8. 7.hdfs工作流程及机制

    1. hdfs基本工作流程 1. hdfs初始化目录结构 hdfs namenode -format 只是初始化了namenode的工作目录 而datanode的工作目录是在datanode启动后自己 ...

  9. AngularJS学习之数据绑定

    既然AngularJS是以数据作为驱动的MVC框架,在上一篇文章中,也介绍了AngularJS如何实现MVC模式的,所有模型里面的数据,都必须经过控制器,才能展示到视图中. 什么是数据绑定 首先来回忆 ...

  10. [CF] Sasha and One More Name

    题目大意 就是给一个回文串,然后进行k次分割,产生k+1个字符子串,通过重新组合这k+1个字符字串,是否会出现新的不同的回文串,且最少需要分割几段.无法产生新的回文串则输出"Impossib ...