[JSOI2009]游戏 二分图博弈
题面
题解
二分图博弈的模板题,只要会二分图博弈就可以做了,可以当做板子打。
根据二分图博弈,如果一个点x在某种方案中不属于最大匹配,那么这是一个先手必败点。
因为对方先手,因此我们就是要找这样一个点。
观察点x的性质,对于这样一个点x,我们一定可以找到一个点来代替它的位置,而什么样的点可以代替它呢?
从x出发,能够到达的未匹配同侧点可以,只需要交换匹配边即可。
因此做几遍dfs就可以了
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define AC 110
#define ac 81000//向四周连边
int n, m, num;
int Head[ac], Next[ac], date[ac], tot;
int link[ac], match[ac], id[AC][AC], a[6] = {-1, 1, 0, 0}, b[6] = {0, 0, -1, 1};
char s[AC][AC];
bool vis[ac], z[ac];
struct node{int x, y;}back[ac];
inline void add(int f, int w)
{
date[++ tot] = w, Next[tot] = Head[f], Head[f] = tot;
date[++ tot] = f, Next[tot] = Head[w], Head[w] = tot;
}
bool dfs(int x)
{
for(R i = Head[x]; i; i = Next[i])
{
int now = date[i];
if(vis[now]) continue;
vis[now] = true;
if(!link[now] || dfs(link[now]))
{
link[now] = x, match[x] = now;
return 1;
}
}
return 0;
}
void cal()
{
memset(link, 0, sizeof(link));
for(R i = 1; i <= num; i ++)
{
if(!(i & 1)) continue;//每次都是从S集合出发的
memset(vis, 0, sizeof(vis)), dfs(i);//不需要知道最大匹配的大小,只需要知道某一种合法方案即可
}
}
void pre()
{
scanf("%d%d", &n, &m), num = n * m;
for(R i = 1; i <= n; i ++) scanf("%s", s[i] + 1);
int tmp1 = 1, tmp2 = 2;
for(R i = 1; i <= n; i ++)
{
for(R j = 1; j <= m; 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 ++)
{
if(s[i][j] == '#') continue;
for(R k = 0; k <= 3; k ++)
{
int x = i + a[k], y = j + b[k];
if(x <= 0 || x > n || y <= 0 || y > m || s[x][y] == '#') continue;
int s = id[i][j], t = id[x][y];
(s & 1) ? add(s, t) : add(t, s);//由编号为奇数的点向编号为偶数的点连边
}
}
}
void dfs1(int x)
{
if(z[x]) return ;
z[x] = true;
for(R i = Head[x]; i; i = Next[i]) dfs1(link[date[i]]);//这样才能保证dfs到的是同侧的点,
}//只有同侧的点才能保证经过的匹配边和非匹配边数量相同,可以互相交换
void dfs2(int x)
{
if(z[x]) return ;
z[x] = true;
for(R i = Head[x]; i; i = Next[i]) dfs2(match[date[i]]);
}
void work()
{
for(R i = 1; i <= num; i ++)
{
if(s[back[i].x][back[i].y] == '#') continue;
if((i & 1) && !match[i]) dfs1(i);
else if(!(i & 1) && !link[i]) dfs2(i);//注意要从同侧的非匹配点dfs到同侧的匹配点,这样才能互换方案
}
bool done = false;
for(R i = 1; i <= n; i ++)
for(R j = 1; j <= m; j ++)
if(z[id[i][j]]) {done = true; break;}
if(!done) {printf("LOSE\n"); return ;}
printf("WIN\n");
for(R i = 1; i <= n; i ++)
for(R j = 1; j <= m; j ++)
if(z[id[i][j]]) printf("%d %d\n", i, j);
/* for(R i = 1; i <= num; i ++) if(z[i]) {done = true; break;}
if(!done) {printf("LOSE\n"); return ;}
printf("WIN\n");
for(R i = 1; i <= num; i ++)
if(z[i]) printf("%d %d\n", back[i].x, back[i].y);*/
}
int main()
{
// freopen("in.in", "r", stdin);
pre();
cal();
work();
// fclose(stdin);
return 0;
}
[JSOI2009]游戏 二分图博弈的更多相关文章
- [NOI2011]兔兔与蛋蛋游戏 二分图博弈
题面 题面 题解 通过观察,我们可以发现如下性质: 可以看做是2个人在不断移动空格,只是2个人能移动的边不同 一个位置不会被重复经过 : 根据题目要求,因为是按黑白轮流走,所以不可能重复经过一个点,不 ...
- [luogu1971 NOI2011] 兔兔与蛋蛋游戏 (二分图博弈)
传送门 Solution 补一篇二分图博弈 这个博客写的很详细qwq: https://www.cnblogs.com/maijing/p/4703094.html Code //By Menteur ...
- BZOJ 1443 游戏(二分图博弈)
新知识get. 一类博弈问题,基于以下条件: 1.博弈者人数为两人,双方轮流进行决策.2.博弈状态(对应点)可分为两类(状态空间可分为两个集合),对应二分图两边(X集和Y集).任意合法的决策(对应边) ...
- luogu4055 游戏 (二分图博弈)
考虑对非障碍的点黑白染色然后做二分图最大匹配,那么有结论,先手必胜当且仅当不是完美匹配,而且可以放的点是那些可以不匹配的点 从非匹配点开始走,后手只能走到匹配点,于是先手就可以走匹配边.由于不能走走过 ...
- BZOJ.2437.[NOI2011]兔兔与蛋蛋游戏(二分图博弈 匈牙利)
题目链接 首先空格的移动等价于棋子在黑白格交替移动(设起点移向白格就是黑色),且不会走到到起点距离为奇数的黑格.到起点距离为偶数的白格(删掉就行了),且不会重复走一个格子. (然后策略就同上题了,只不 ...
- [模板] 二分图博弈 && BZOJ2463:[中山市选2009]谁能赢呢?
二分图博弈 from BZOJ 1443 游戏(二分图博弈) - free-loop - 博客园 定义 1.博弈者人数为两人,双方轮流进行决策. 2.博弈状态(对应点)可分为两类(状态空间可分为两个集 ...
- BZOJ1443: [JSOI2009]游戏Game
如果没有不能走的格子的话,和BZOJ2463一样,直接判断是否能二分图匹配 现在有了一些不能走的格子 黑白染色后求出最大匹配 如果是完备匹配,则无论如何后手都能转移到1*2的另一端,故先手必输 否则的 ...
- JSOI2009 游戏
1443: [JSOI2009]游戏Game Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 557 Solved: 251[Submit][Stat ...
- 【BZOJ】1443: [JSOI2009]游戏Game
[算法]博弈论+二分图匹配(最大流) [题解]方格图黑白染色得到二分图, 二分图博弈:当起点不属于某个最大匹配时,后手必胜. 问题转化为那些点不属于某个最大匹配. 先找到一个最大匹配,非匹配点加入答案 ...
随机推荐
- maven 发布springboot项目
1.把Spring Boot打包成JAR的形式,需要在pom.xml文件对应以下代码 <build> <finalName>ljl</finalName> //打包 ...
- idea 安装后需要手动设置 64位的vmoptions (为了更好的性能和体验)
- 七、Django之Views
一.概述 视图就是python中的函数,我们通常也称为:视图函数. 视图一般被定义在“app/views.py”中. 视图负责接受Web请求(HttpRequest)URL,进行逻辑处理,并返回Web ...
- 深入解析QML引擎, 第2部分: 绑定(Bindings)
原文 QML Engine Internals, Part 2: Bindings 译者注:这个解析QML引擎的文章共4篇,分析非常透彻,在国内几乎没有找到类似的分析,为了便于国内的QT/QML爱好 ...
- Java or Python?测试开发工程师如何选择合适的编程语言?
很多测试开发工程师尤其是刚入行的同学对编程语言和技术栈选择问题特别关注,毕竟掌握一门编程语言要花不少时间成本,也直接关系到未来的面试和就业(不同企业/项目对技术栈要求也不一样),根据自身情况做一个相对 ...
- Android 8.0 NavigationBar 颜色问题。
1. packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java public void on ...
- tcp三次握手 四次挥手 (转)
转自: http://blog.csdn.net/whuslei/article/details/6667471 建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看 ...
- 第五次作业psp
psp 进度条 代码累积折线图 博文累积折线图 psp饼状图 团体合作体会:经过这几天的团队,我感受良多.发现团队协作是一件非常让人兴奋的事情.团队成员们互相帮助,互相协作,让我感受最深的就是当自己为 ...
- tensorboard入门
Tensorboard tensorboard用以图形化展示我们的代码结构和图形化训练误差等,辅助优化程序 tensorboard实际上是tensorflow机器学习框架下的一个工具,需要先安装ten ...
- web会员注册页面代码(4)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...