传送门

题意:

给出一个\(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. luoguP1447 [NOI2010]能量采集

    https://www.luogu.org/record/22874213 题目大意:给定n和m,求Σ(1<=i<=n)Σ(1<=j<=m)GCD(i,j)* 2-1 i和j的 ...

  2. Jmeter+Jenkins的HTML报告中添加QPS、90%栏目显示

    1.进入jmeter/extras目录,修改 jmeter-results-detail-report_21.xsl   2.打开文件 在summary部分修改如下: 在pagelist部分修改如下: ...

  3. C++ class 内的 [] 重载示例。

    #include <iostream> // overloading "operator [] " inside class ///////////////////// ...

  4. BZOJ4027/LG4107 「HEOI2015」兔子与樱花 树形DP+贪心

    问题描述 LG4107 题解 首先,我们可以直接令结点 \(x\) 的权值为 \(c[x]+son_x\) ,发现将 \(x,y\) 合并,相当于增加 \(c[x]+c[y]-1\) 的重量. 容易想 ...

  5. Windows Azure Virtual Machine (38) 跨租户迁移使用托管磁盘的Azure虚拟机

    <Windows Azure Platform 系列文章目录> 背景介绍: (1)我们建议使用Azure Manage Disk托管磁盘来创建Azure虚拟机 (2)使用托管磁盘的好处是, ...

  6. 一文读懂前端技术演进:盘点Web前端20年的技术变迁史

    本文原文由作者“司徒正美”发布于公众号“前端你别闹”,即时通讯网收录时有改动,感谢原作者的分享. 1.引言 1990 年,第一个Web浏览器的诞生:1991 年,WWW诞生,这标志着前端技术的开始. ...

  7. centos6系统资源限制

    1.限制用户CPU使用资源 /etc/security/limits.conf #主配置文件 /etc/security/limits.d/ #子模块配置文件 新建一个普通用户,并查看默认资源限制 [ ...

  8. Kafka学习笔记之Kafka性能测试方法及Benchmark报告

    0x00 概述 本文主要介绍了如何利用Kafka自带的性能测试脚本及Kafka Manager测试Kafka的性能,以及如何使用Kafka Manager监控Kafka的工作状态,最后给出了Kafka ...

  9. 练手WPF(四)——贪吃蛇小游戏的简易实现(上)

    一. 游戏界面首先,按照惯例,编辑MainWindow.xaml,先将游戏界面制作好.非常简单:(1)主游戏区依然使用我们熟悉的Canvas控件,大小为640X480像素,设定每小格子为20px,所以 ...

  10. Java问题记录——IllegalMonitorStateException

    Java问题记录——IllegalMonitorStateException 摘要:本文主要分析了IllegalMonitorStateException的产生原因. 部分内容来自以下博客: http ...