例题:在N×M的迷宫中有一个棋子,小 AA 首先任意选择棋子放置的位置。然后,小 YY 和小 AA 轮流将棋子移动到相邻的格子里。游戏的规则规定,在一次游戏中,同一个格子不能进入两次,且不能将棋子移动到某些格子中去。当玩家无法继续移动棋子时,游戏结束,最后一个移动棋子的玩家赢得了游戏。

输入格式:输入数据首先输入两个整数 N,M,表示了迷宫的边长。接下来 N行,每行 M个字符,描述了迷宫。

输出格式:若小 AA 能够赢得游戏,则输出一行 WIN,然后输出所有可以赢得游戏的起始位置,按行优先顺序输出,每行一个。否则输出一行 LOSE

分析:发现每次移动一定是从一个黑点到达一个白点,或者反过来。所以可以对于棋盘进行染色然后连边。

考虑一下必胜策略。如果选择从一个匹配点开始走,另外一个人沿着匹配点走,那么就输了,因为匹配点不一定有出边了。如果选择从一个非匹配点开始走,另外一个人无论怎么走都只能走到一个匹配点(或者无路可走),因为如果另外一个人可以走到一个非匹配点,意味着这两个点可以匹配,所以不存在这种情况。那么,先手只需要沿着匹配边走就一定能够做到必胜。所以黑白染色之后连边,找到所有不一定在最大匹配中的点就好了。跑网络流就会快很多。但是怎么判断一个点是否在不一定在最大匹配中呢?把所有和S相连的(还有剩余流量的边连接的)点全部扣下来,这些点一定满足条件。为什么呢?首先不在当前的这个匹配中的点一定会被计算。如果一个点在匹配中,但是他被连上了,那么一定是通过一个没有被匹配上的点,到达当前点的匹配点,在连回来的,这样子意味着可以交换匹配。和T相连的点同理解决即可。

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int M = 105;
const int N = 1e4 + 50; typedef long long ll; int S, T, cnt = 1, maxn, tot, dn, dm, ans;
int dep[N], head[N], temp[N], id[M][M], kk[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
char s[M][M];
bool vis[N], is[N], color[N]; struct Edge{
int nex, to, val;
}e[N << 3]; inline int min(int a, int b) { return a < b ? a : b; }
inline void add(int a, int b, int c){
e[++cnt] = {head[a], b, c}, head[a] = cnt;
e[++cnt] = {head[b], a, 0}, head[b] = cnt;
} bool bfs(){
memset(dep, 0, sizeof(dep));
queue<int> q;
q.push(S); dep[S] = 1;
while(!q.empty()){
int u = q.front(); q.pop();
for(int i = head[u]; i; i = e[i].nex){
int to = e[i].to;
if(!dep[to] && e[i].val){
dep[to] = dep[u]+1;
q.push(to);
}
}
}
return dep[T];
} ll dfs(int u, int flow){
if(u == T) return flow;
ll out = 0, k;
for(int i = temp[u]; i && flow; i = e[i].nex){
temp[u] = i;
if(!e[i].val) continue;
int to = e[i].to;
if(dep[to] == dep[u]+1 && (k = dfs(to,min(flow,e[i].val)))){
e[i].val -= k;
e[i^1].val += k;
flow -= k; out += k;
}
}
if(!out) dep[u] = 0;
return out;
} void Dinic(){
while(bfs()){
for(int i = S; i <= T; ++i) temp[i] = head[i];
maxn += dfs(S, 1e9);
}
} void DFS(int u, int k){
vis[u] = 1;
if(color[u] == k) ++ans, is[u] = 1;
for(int i = head[u]; i; i = e[i].nex){
int to = e[i].to;
if(e[i].val == k && !vis[to]) DFS(to, k);
}
} int main(){
scanf("%d%d", &dn, &dm);
for(int i = 1; i <= dn; ++i) scanf("%s", s[i] + 1);
for(int i = 1; i <= dn; ++i)
for(int t = 1; t <= dm; ++t)
if(s[i][t] != '#') id[i][t] = ++tot;
T = tot + 1;
for(int i = 1; i <= dn; ++i)
for(int t = 1; t <= dm; ++t)
if(s[i][t] == '.'){
if(((i + t) & 1)){
add(S, id[i][t], 1), color[id[i][t]] = 1;
for(int j = 0; j < 4; ++j){
int dx = i + kk[j][0], dy = t + kk[j][1];
if(dx >= 1 && dx <= dn && dy >= 1 && dy <= dm)
add(id[i][t], id[dx][dy], 1);
}
}
else add(id[i][t], T, 1);
}
Dinic(); DFS(S, 1); memset(vis, 0, sizeof(vis)); DFS(T, 0);
if(ans){
puts("WIN");
for(int i = 1; i <= dn; ++i)
for(int t = 1; t <= dm; ++t)
if(is[id[i][t]]) printf("%d %d\n", i, t);
}
else puts("LOSE");
return 0;
}

洛谷4055 [JSOI2009]游戏(二分图博弈)的更多相关文章

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

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

  2. 洛谷 P2197 nim游戏

    洛谷 P2197 nim游戏 题目描述 甲,乙两个人玩Nim取石子游戏. nim游戏的规则是这样的:地上有n堆石子(每堆石子数量小于10000),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取 ...

  3. 洛谷 P1965 转圈游戏

    洛谷 P1965 转圈游戏 传送门 思路 每一轮第 0 号位置上的小伙伴顺时针走到第 m 号位置,第 1 号位置小伙伴走到第 m+1 号位置,--,依此类推,第n − m号位置上的小伙伴走到第 0 号 ...

  4. 洛谷 P1000 超级玛丽游戏

    P1000 超级玛丽游戏 题目背景 本题是洛谷的试机题目,可以帮助了解洛谷的使用. 建议完成本题目后继续尝试P1001.P1008. 题目描述 超级玛丽是一个非常经典的游戏.请你用字符画的形式输出超级 ...

  5. 【流水调度问题】【邻项交换对比】【Johnson法则】洛谷P1080国王游戏/P1248加工生产调度/P2123皇后游戏/P1541爬山

    前提说明,因为我比较菜,关于理论性的证明大部分是搬来其他大佬的,相应地方有注明. 我自己写的部分换颜色来便于区分. 邻项交换对比是求一定条件下的最优排序的思想(个人理解).这部分最近做了一些题,就一起 ...

  6. $loj10156/$洛谷$2016$ 战略游戏 树形$DP$

    洛谷loj Desription Bob 喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的方法.现在他有个问题. 现在他有座古城堡,古城堡的路形成一棵树.他要在这棵树的节点上放置最少数 ...

  7. 洛谷P1000 超级玛丽游戏(洛谷新手村1-1-1)

    题目背景 本题是洛谷的试机题目,可以帮助了解洛谷的使用. 建议完成本题目后继续尝试P1001.P1008. 题目描述 超级玛丽是一个非常经典的游戏.请你用字符画的形式输出超级玛丽中的一个场景. *** ...

  8. 洛谷P1080 国王游戏 python解法 - 高精 贪心 排序

    洛谷的题目实在是裹脚布 还编的像童话 这题要 "使得获得奖赏最多的大臣,所获奖赏尽可能的少." 看了半天都觉得不像人话 总算理解后 简单说题目的意思就是 根据既定的运算规则 如何排 ...

  9. 洛谷P1290欧几里德游戏

    题目地址 题目大意: 两个人st和ol博弈 有两个整数n,m 每次轮到一个人时候,需要选择用大的那个数减去小的那个数的倍数(不能减为负数) 最后得到0的为胜利者 思路: (以下讨论均在n<m的条 ...

  10. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

随机推荐

  1. jdk安装自动化

    写个在linux环境安装Java的脚本(install_java.sh),只需将jdk上传至/opt目录下,执行脚本即可. #!/bin/bash #author:zhangyl #本安装使用jdk版 ...

  2. GAN!生成对抗网络GAN全维度介绍与实战

    本文为生成对抗网络GAN的研究者和实践者提供全面.深入和实用的指导.通过本文的理论解释和实际操作指南,读者能够掌握GAN的核心概念,理解其工作原理,学会设计和训练自己的GAN模型,并能够对结果进行有效 ...

  3. python 面试题第一弹

    1. 如何理解Python中的深浅拷贝 浅拷贝(Shallow Copy)创建一个新的对象,该对象的内容是原始对象的引用.这意味着新对象与原始对象共享相同的内存地址,因此对于可变对象来说,如果修改了其 ...

  4. LeetCode--1039

    Smiling & Weeping ----我总是躲在梦与季节的身处, 听花与黑夜唱尽梦魇, 唱尽繁华,唱断所有记忆的来路. 题目链接:1039. 多边形三角剖分的最低得分 - 力扣(Leet ...

  5. T-SQL——关于数据合并(Merge)

    目录 0. 背景说明及测试数据 1. 直接清空,重新插入 2. 单条记录执行插入.更新操作 3. Merge函数 3.1 准备测试数据 3.2 测试Merge 3.3 关于Merge 4.参考 sha ...

  6. Visual Studio必备插件

    1.Rainbow Braces 2.Codist 3.ResXManager 4.XAML Styler for Visual Studio 2022 5.Viasfora 6.ZenCoding ...

  7. Solution -「洛谷 P5176」公约数

    Description Link. 求 \[\sum_{i=1}^n\sum_{j=1}^m\sum_{k=1}^p\gcd(i\cdot j,i\cdot k,j\cdot k)\times \gc ...

  8. 算法打卡|Day5 哈希表part01

    哈希表 part01 今日任务 ● 哈希表理论基础 ● 242.有效的字母异位词 ● 349. 两个数组的交集 ● 202. 快乐数 ● 1. 两数之和 目录 哈希表 part01 链表理论基础 Pr ...

  9. Python基础——数字类型int与float、字符串、列表、元组、字典、集合、可变类型与不可变类型、数据类型总结

    文章目录 一 引子 二 数字类型int与float 2.1 定义 2.2 类型转换 2.3 使用 三 字符串 3.1 定义: 3.2 类型转换 3.3 使用 3.3.1 优先掌握的操作 3.3.2 需 ...

  10. 2023_10_10_MYSQL_DAY_02_笔记

    2023_10_10_MYSQL_DAY_02_笔记 #在 FROM 子句中使用子查询 SELECT a.ename, a.sal, a.deptno, b.salavg FROM emp a, (S ...