例题:在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. [mysql]安全加固

    前言 因等保安全的要求,需要对MySQL用户密码和登录策略进行安全加固,以满足以下需求: 密码至少8位,包含大小写字母.数字和特殊字符. 当密码登录失败一定次数后锁定账户. 密码90天过期 本文使用的 ...

  2. centos7升级内核到最新稳定版

    前言 centos7默认的内核版本才3.10,诸如VXLAN.eBPF等特性无法体验,因此需要升级.目前(2022.02)Linux的内核版本已更新到5.16. 步骤 更新仓库 yum update ...

  3. C#性能优化-树形结构递归优化

    前言 大家好,我是wacky,最近在工作中遇到一个有趣的问题,同事反馈说WPF中有一个树形结构的集合,在加载时会直接报堆栈溢出,一直没时间(懒得)看,导致很久了也没人解决掉.于是,组长就把这个&quo ...

  4. 遥遥领先 spring,中国人的 solon 来啦!10% 的体积,10倍的速度

    Solon 是什么? Java 生态型应用开发框架.它从零开始构建,有自己的标准规范与开放生态(历时五年,已有全球第二级别的生态规模).与其他框架相比,它解决了两个重要的痛点:启动慢,费内存.2023 ...

  5. 《高级程序员 面试攻略 》RabbitMQ 如何实现可靠性

    RabbitMQ 提供了多种机制来实现消息传递的可靠性.下面是一些常见的方法: 1. 持久化消息:RabbitMQ 允许将消息标记为持久化,以确保即使在发生故障或重启后,消息也不会丢失.通过将消息的` ...

  6. Codespaces个性化后台服务器配置指南

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 前文概览 在前文<浏览器上写代码,4核8G微软服 ...

  7. API对接需求如何做需求调研,需要注意什么?

    随着互联网的发展,越来越多的企业开始将自己的业务系统通过API接口与其他系统进行对接,以便于数据的共享.协同操作等.在进行API对接之前,需要对用户需求进行深入的调研,以便于能够准确的设计出满足用户需 ...

  8. Java读取某个文件夹下的所有文件(支持多级文件夹)

    源码如下: package com.vocy.water.batch; import java.io.FileNotFoundException; import java.io.IOException ...

  9. [htmlayout] picture标签替代img, 解决更新图片数据后依然显示原图片数据

    在hl中, 你可能遇到过这样的情况.   给img标签设置了一个图片路径.   在软件使用过程中对这个路径的数据进行过重写, 删除等等 但img依然还是显示最初载入的图片数据. 解决办法: 用&quo ...

  10. JS深入学习笔记 - 第一章.构造函数原型与原型链

    1.构造函数和原型 1.1 概述 在典型的 OOP语言中(如Java),都存在类的概念,类就是对象的模板,对象就是类的实例,但在ES6之前,JS并没有引入类的概念. 在ES6之前,对象不是基于类创建的 ...