传送门

题意:

给出一个\(n*m\)的迷宫,有\(a\)个入口,\(b\)个出口。

现在有\(a\)个机器人都从入口出发,一开始方向默认为下,你可以选在在一些格子上面放置一个转向器,转向器有四种:

  • 向下走变为向右走;
  • 向下走变为向左走;
  • 向上走变为向右走;
  • 向上走变为向左走。

每个格子最多放一个转向器。

问最后是否存在一种方案,使得每个机器人都能到达从其中一个出口。

思路:

因为题目要求转向器只能接受固定方向,并且变为固定方向,所以有几个比较重要的观察:

  • 不存在两个机器人的路线共线;
  • 若一个格子上存在转向器,那么至多只能经过一个机器人;
  • 若一个格子上没有转向器,那么可以经过两个方向垂直的机器人。

观察一挺好证明,若存在两个机器人共方向,说明其中一个机器人经过转向器,而另一个没有经过,出现矛盾。后面几个yy一下应该好理解。

所以现在问题就是,一个格子只能横向经过或竖向经过,若经过转换器,只能经过一次,问能否使得\(a\)个机器人成功走到终点。

考虑网络流,我们将点拆成两类:一类是“水平”类点,另一类是“垂直”类点。那么一开始我们有水平和水平的相连,垂直的和垂直的相连,流量为\(1\)。

考虑经过转换器时,方向发生了变化,那么我们对于一个点,允许其向另一个方向转化,流量为\(1\)。

容易发现这样的建图刚好符合上面的要求。

PS:网上代码很多都是错的,因为没有考虑到障碍物的情况,注意一下最后到出口时,是否能到达\((n,x)\)这个点。

细节见代码:

#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
//#define Local
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 50005; #define INF 0x3f3f3f3f
template <class T>
struct Dinic{
struct Edge{
int v, next;
T flow;
Edge(){}
Edge(int v, int next, T flow) : v(v), next(next), flow(flow) {}
}e[N * 30];
int head[N], tot;
int dep[N];
void init() {
memset(head, -1, sizeof(head)); tot = 0;
}
void adde(int u, int v, T w, T rw = 0) {
e[tot] = Edge(v, head[u], w);
head[u] = tot++;
e[tot] = Edge(u, head[v], rw);
head[v] = tot++;
}
bool BFS(int _S, int _T) {
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].next) {
int v = e[i].v;
if(!dep[v] && e[i].flow > 0) {
dep[v] = dep[u] + 1;
q.push(v);
}
}
}
return dep[_T] != 0;
}
T dfs(int _S, int _T, T a) {
T flow = 0, f;
if(_S == _T || a == 0) return a;
for(int i = head[_S]; ~i; i = e[i].next) {
int v = e[i].v;
if(dep[v] != dep[_S] + 1) continue;
f = dfs(v, _T, min(a, e[i].flow));
if(f) {
e[i].flow -= f;
e[i ^ 1].flow += f;
flow += f;
a -= f;
if(a == 0) break;
}
}
if(!flow) dep[_S] = -1;
return flow;
}
T dinic(int _S, int _T) {
T max_flow = 0;
while(BFS(_S, _T)) max_flow += dfs(_S, _T, INF);
return max_flow;
}
}; Dinic <int> solve; int n, m, a, b;
char mp[105][105]; int id(int x, int y) {
return (x - 1) * m + y;
} bool ok(int x, int y) {
return x >= 1 && x <= n && y >= 1 && y <= m && mp[x][y] != '1';
} void run() {
solve.init();
cin >> n >> m >> a >> b;
int base = (n + 1) * m;
int s = 0, t = 2 * base + 1;
for(int i = 1; i <= n; i++) {
cin >> (mp[i] + 1);
}
for(int i = 1; i <= a; i++) {
int x; cin >> x;
solve.adde(s, id(1, x), 1);
}
for(int i = 1; i <= b; i++) {
int x; cin >> x;
solve.adde(id(n, x), t, 1);
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
if(mp[i][j] == '1') continue;
if(ok(i - 1, j)) solve.adde(id(i, j), id(i - 1, j), 1);
if(ok(i + 1, j)) solve.adde(id(i, j), id(i + 1, j), 1);
if(ok(i, j - 1)) solve.adde(id(i, j) + base, id(i, j - 1) + base, 1);
if(ok(i, j + 1)) solve.adde(id(i, j) + base, id(i, j + 1) + base, 1);
solve.adde(id(i, j), id(i, j) + base, 1);
solve.adde(id(i, j) + base, id(i, j), 1);
}
}
if(solve.dinic(s, t) == a) cout << "Yes" << '\n';
else cout << "No" << '\n';
} int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
#ifdef Local
freopen("../input.in", "r", stdin);
freopen("../output.out", "w", stdout);
#endif
int T; cin >> T;
while(T--) run();
return 0;
}

较完整题解:hhh

2019CCPC 秦皇岛 E.Escape的更多相关文章

  1. [CCPC2019秦皇岛] E. Escape

    [CCPC2019秦皇岛E] Escape Link https://codeforces.com/gym/102361/problem/E Solution 观察到性质若干然后建图跑最大流即可. 我 ...

  2. 2019CCPC秦皇岛 E题 Escape(网络流)

    Escape Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Su ...

  3. 2019-ccpc秦皇岛现场赛

    https://www.cnblogs.com/31415926535x/p/11625462.html 昨天和队友模拟了下今年秦皇岛的区域赛,,,(我全程在演 题目链接 D - Decimal 签到 ...

  4. 2019CCPC秦皇岛D题 Decimal

    Decimal Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total S ...

  5. 2019CCPC秦皇岛I题 Invoker(DP)

    Invoker Time Limit: 15000/12000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total ...

  6. 2019CCPC秦皇岛 F Forest Program

    队友过的:https://blog.csdn.net/liufengwei1/article/details/101632506 Forest Program Time Limit: 2000/100 ...

  7. 2019CCPC秦皇岛 J MUV LUV EXTRA(KMP)

    MUV LUV EXTRA Time Limit: 2000/1500 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)T ...

  8. 2019CCPC秦皇岛 K MUV LUV UNLIMITED(博弈)

    MUV LUV UNLIMITED Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  9. 2019CCPC秦皇岛自我反省&部分题解

    练了一年半了,第一次打CCPC,险些把队友坑了打铁,最后也是3题危险捡了块铜. 非常水的点双连通,我居然不相信自己去相信板子,唉,结果整来整去,本来半个小时能出的题,整到了3个小时,大失误呀,不然就可 ...

随机推荐

  1. 8.gitlab 邮件设置

    这个我没做实验.  视屏里面说的 126的 邮箱限制少点. 建议用126的 邮箱. 参考视屏  jenkins+gitlab+插件\1\7(07-gitlab备份恢复)   最后的一点部分. 需要在配 ...

  2. pwn-pwn2

    环境说明 Ubuntu 16.04 pwntool IDA gdb-peda 先丢到Ubuntu看看文件的类型  64位 然后看看保护机制,发现没有保护机制 然后丢到IDA看看  F5查看伪代码 ma ...

  3. wafer2-nodejs 本地部署服务器

    友情提示:假设你已经部署好了腾讯云微信小程序服务,如果没有,就不用往下看了,果断选云开发. ------------------------------------------------------ ...

  4. VScode Python 虚拟环境

    安装python环境 在VScode里设置Python 虚拟环境查找路径(Settings -> Extensions -> Python Configurations -> Env ...

  5. 【2019.7.20 NOIP模拟赛 T2】B(B)(数位DP)

    数位\(DP\) 首先考虑二进制数\(G(i)\)的一些性质: \(G(i)\)不可能有连续两位第\(x\)位和第\(x+1\)位都是\(1\).因为这样就可以进位到第\(x+2\)位.其余情况下,这 ...

  6. 阿里Sentinel整合Zuul网关详解

    前面我们讲解了Sentinel整合Spring Cloud Gateway,详细请查看文章:阿里Sentinel支持Spring Cloud Gateway啦 目前来说,大部分公司线上的网关应该是Zu ...

  7. java4wifidog_server_README

    项目地址:https://github.com/C-hill/java4wifidog_server 开发环境:Windows  JDK7  Tomcat6  Myeclipse8.5  MySQL5 ...

  8. 1+x 证书 Web 前端开发 CSS3 专项练习

    官方QQ群 1+x 证书 Web 前端开发 CSS3 专项练习 http://blog.zh66.club/index.php/archives/196/

  9. idea2019最新注册码(亲测有效)

    序言 最近发现经常用的idea注册用的License Server 又不能用了,估计是被"约谈了".内容如下: 虽然Community版本是免费使用的,但是在使用的过程中会出现各种 ...

  10. 解决MybatisPlus修改时空字段不修改问题

    今天遇到了一个问题,在更新数据时,MybatisPlus不会进行修改属性为空的数据表字段. 解决办法: 只需要在实体类的属性上加一行注释即可 /** * 姓名 */ @TableField(fill ...