[洛谷P2472] [SCOI2007]蜥蜴
题目链接:
题目分析:
一道网络流,先来分析一下问题:
在一个\(r*c\)的图中分布了一些数,其他地方都用\(0\)填充,我们分别从指定的一些数出发,每次可以移动到周围距离为\(d\)以内的数上(或图外),原来的数会被\(-1\),任何时候数不能为负。各个数走法之间互相影响。问至多有多少个数出发能到达图外?
把这个题的限制条件列出来一下吧:
- 每个石柱只能站一只蜥蜴
- 每个石柱最多被经过其高度次
- 石柱与石柱之间,石柱与图边界之间要距离小于等于\(d\)才能到达
首先我的角度是以每个石柱本身的限制条件入手。我们知道一个高度为\(h\)的石柱最多可以被经过\(h\)次(显然,蜥蜴是不走回头路的,因为这是对资源的浪费),而网络流的基本性质之一,是每条边最多将其上限流满(相当于有一个上限),那么可以考虑将石柱的高度作为网络流建图边上的限制。但是每个石柱是一个点,怎么办呢,我们就考虑把每个石柱拆点,把编号为\(i\)的点拆成\(i\)和\(i + r * c\),然后把流入这个点的边全部接到\(i\)上,流出这个点的边全部接到\(i+r*c\)上,把限制加在两点之间的连边上(流量为\(h\))。这是对于石柱的处理,也是我认为这个问题中最关键的一步。
剩下的就比较好办了。
对于“每个石柱只能站一只蜥蜴”的限制条件,将“只能站一只”作为上界,源点向蜥蜴所在的每个石柱连边,边容量为\(1\)
对于石柱和石柱之间,石柱与图边界之间距离小于等于\(d\)才能到达的限制条件,因为图很小,我们考虑直接暴力枚举两个点,如果两个点都有石柱且距离小于等于\(d\),那么我们直接考虑两个石柱之间连一条容量为\(INF\)的边:除了距离,没有别的限制条件了,而距离的限制条件已经判断过了,并且每个石柱的限制已经在拆点的过程中加上去了,所以容量不需要做其他的限制,直接连\(INF\)即可。对于到达边界的限制条件,我们同样连一条\(INF\)的边(和前面的原因类似),距离判断只需要判断横纵就行,因为根据勾股定理,横纵都比\(d\)大显然斜着也比\(d\)大。
代码:
// luogu-judger-enable-o2
#include <bits/stdc++.h>
#define INF (1000000000 + 7)
#define N (10005 + 5)
#define M (100000 + 5)
#define int long long
using namespace std;
inline int read(){
int cnt = 0, f = 1; char c;
c = getchar();
while (!isdigit(c)) {
if(c == '-') f = -f;
c = getchar();
}
while (isdigit(c)) {
cnt = cnt * 10 + c - '0';
c = getchar();
}
return cnt * f;
}
int r, c, d, tot = 1, n;
int S, T;
int first[M], nxt[M], to[M], flow[M];
int mapp[N][N], a[N][N];
int dep[M], cnt[M];
char lizard[N][N];
inline void Add(int x, int y, int z) {
nxt[++tot] = first[x], first[x] = tot, to[tot] = y, flow[tot] = z;
nxt[++tot] = first[y], first[y] = tot, to[tot] = x, flow[tot] = 0;
}
inline bool pd(int i, int j) {
if (i <= d || j <= d) return true;
if (r - i + 1 <= d || c - j + 1 <= d) return true;
return false;
}
inline void build() {
S = 1;
for (register int i = 1; i <= r; i++)
for (register int j = 1; j <= c; j++)
a[i][j] = ++tot;
for (register int i = 1; i <= r; i++)
scanf("%s", lizard[i] + 1);
for (register int i = 1; i <= r; i++)
for (register int j = 1; j <= c; j++)
mapp[i][j] = lizard[i][j] - '0';
T = r * c * 2 + 2, tot = 1;
for (register int i = 1; i <= r; i++)
scanf("%s", lizard[i] + 1);
for (register int i = 1; i <= r; i++)
for (register int j = 1; j <= c; j++)
if (mapp[i][j]) {
Add(a[i][j], a[i][j] + r * c, mapp[i][j]);
if (pd(i, j)){
Add(a[i][j] + r * c, T, INF);
// cout<<i<<" "<<j<<endl;
}
}
for (register int i = 1; i <= r; i++)
for (register int j = 1; j <= c; j++)
for (register int k = 1; k <= r; k++)
for (register int p = 1; p <= c; p++) {
if (i == k && j == p) continue;
if (mapp[i][j] && mapp[k][p])
if ((i - k) * (i - k) + (j - p) * (j - p) <= d * d)
Add(a[i][j] + r * c, a[k][p], INF);
// Add(a[k][p] + r * c, a[i][j], INF);
}
for (register int i = 1; i <= r; i++)
for (register int j = 1; j <= c; j++)
if (lizard[i][j] == 'L') Add(S, a[i][j], 1), ++n;
}
inline void bfs_(int s) {
memset(dep, 0xff, sizeof(dep));
dep[s] = 0;
cnt[0] = 1;
queue<int> q;
q.push(s);
while (!q.empty()) {
int p = q.front();
q.pop();
for (register int i = first[p]; i >= 2; i = nxt[i]) {
int v = to[i];
if (dep[v] == -1) {
++cnt[dep[v] = dep[p] + 1];
q.push(v);
}
}
}
}
int max_flow;
int dfs_(int p, int f) {
if (p == T) {
max_flow += f;
return f;
}
int u = 0;
for (register int i = first[p]; i >= 2; i = nxt[i]) {
int v = to[i];
if (flow[i] && dep[v] == dep[p] - 1) {
int uu = dfs_(v, min(flow[i], f - u));
if (uu) {
flow[i] -= uu;
flow[i ^ 1] += uu;
u += uu;
}
if (u >= f) {
return u;
}
}
}
if (!--cnt[dep[p]]) {
dep[S] = r * c * 2 + 10;
}
++cnt[++dep[p]];
return u;
}
signed main() {
r = read(); c = read(); d = read();
build();
bfs_(T);
while (dep[S] < 2 * r * c + 9) dfs_(S, INF);
printf("%lld", n - max_flow);
return 0;
}
[洛谷P2472] [SCOI2007]蜥蜴的更多相关文章
- 洛谷P2472 [SCOI2007]蜥蜴 题解
题目链接: https://www.luogu.org/problemnew/show/P2472 分析: 这道题用最大流解决. 首先构建模型. 一根柱子可以跳入和跳出,于是拆成两个点:入点和出点. ...
- P2472 [SCOI2007]蜥蜴(网络流)
P2472 [SCOI2007]蜥蜴 把每个点拆成2个点,两点之间连边的边权为石柱高度 新建虚拟源点$S$和汇点$T$ $S$向所有有蜥蜴的点连边,边权1 其他边都连$inf$ 剩下就是裸的$dini ...
- P2472 [SCOI2007]蜥蜴(网络最大流)
P2472 [SCOI2007]蜥蜴 题目描述 在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外. 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距 ...
- P2472 [SCOI2007]蜥蜴 (最大流)
题目 P2472 [SCOI2007]蜥蜴 解析 这个题思路比较清晰,本(qi)来(shi)以(jiu)为(shi)无脑建图跑最大流,结果挂了,整了一个小时后重新建图才过的. 建立一个超级源点和一个超 ...
- P2472 [SCOI2007]蜥蜴(最大流)
P2472 [SCOI2007]蜥蜴 自己第一道独立做题且一遍AC的网络流题纪念... 看到这道题我就想到网络流建图的方式了... 首先根据每个高度,我们将每个点拆成两个点限流.之后根据跳的最大距离, ...
- 【洛谷 P2472】 [SCOI2007]蜥蜴 (最大流)
题目链接 简单网络流. 源点向蜥蜴连流量为\(1\)的边. 能跳出去的点向汇点连流量为\(INF\)的边. 把每个点拆成\(2\)个点,\(O(n^4)\)枚举两两点,如果距离小于等于\(d\),就互 ...
- 洛谷$P$2472 蜥蜴 $[SCOI2007]$ 网络流
正解:网络流 解题报告: 传送门! $umm$一看就是个最大流呗,,,就直接考虑怎么建图趴$QwQ$ 首先看到这个高度减小其实就相当于对这个点的次数有约束,就显然拆点呗,流量为高度 然后$S$连向左侧 ...
- 【题解】Luogu P2472 [SCOI2007]蜥蜴
原题传送门 题目要求无法逃离的最少有多少 直接做肯定不好做,我们帮题目变一个说法:最多能逃离多少 这个询问一看就是最大流 考虑如何建图: 1.将S和每一个有蜥蜴的点连一条流量为1的边(每个蜥蜴只能用1 ...
- 洛谷 P2053 [SCOI2007]修车 解题报告
P2053 [SCOI2007]修车 题目描述 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M位技术 ...
随机推荐
- spring data jpa使用 (转:http://www.manongjc.com/article/25284.html#four_1_7)
Jap相关的使用 时间:2018-12-18 本文章向大家介绍Jap相关的使用,主要包括Jap相关的使用使用实例.应用技巧.基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下. ...
- asp.net core2.0 依赖注入 AddTransient与AddScoped的区别 - 晓剑 - CSDN博客
原文:asp.net core2.0 依赖注入 AddTransient与AddScoped的区别 - 晓剑 - CSDN博客 原文地址:http://www.tnblog.net/aojiancc2 ...
- Pod 私有仓库构建
Pod 私有仓库构建 创建`私有仓库索引库`(iOS) 添加`私有仓库索引库`到本地repo管理 创建自己的`组建库工程 上传`组建库工程`到`私有仓库索引库` App工程调用`组建库工程` 目的 私 ...
- sql(7)
EXCEPT是指在第一个集合中存在,但是不存在于第二个集合中的数据. EXCEPT 子句/运算符用于将两个 SELECT 语句结合在一起,并返回第一个 SELECT 语句的结果中那些不存在于第二个 S ...
- Bugs Integrated, Inc.
Bugs Integrated, Inc. 给出一个\(n\times m\)的矩形网格图,给出其中K个障碍物的位置,求其中最多能摆的\(2\times 3\)的矩形的个数,\(n\leq 150,m ...
- [转]Nginx配置详解
Nginx是lgor Sysoev为俄罗斯访问量第二的rambler.ru站点设计开发的.从2004年发布至今,凭借开源的力量,已经接近成熟与完善. Nginx功能丰富,可作为HTTP服务器,也可作为 ...
- jquery学习笔记(二):DOM元素操作
内容来自[汇智网]jquery学习课程 2.1 元素属性操作 1.获取元素的属性 语法:attr(name) 参数name表示属性的名称 2.设置元素的属性 单个属性设置语法:attr(key,val ...
- 8种形式的Android Dialog使用举例
在Android开发中,我们经常会需要在Android界面上弹出一些对话框,比如询问用户或者让用户选择.这些功能我们叫它Android Dialog对话框,在我们使用Android的过程中,我归纳了一 ...
- FP function programming
fp是函数式编程,也是一种编程方法,同面向对象的编程方法一样. 所谓的functional programming 就是函数式编程,这也是一种编程方法,或者说是编程模式,同面向过程的编程,以及面向对象 ...
- os.path.basename()
返回path最后的文件名.如果path以/或\结尾,那么就会返回空值.即os.path.split(path)的第二个元素. >>> import os >>> p ...