先导知识

网络最大流

题目链接

https://vjudge.net/problem/ZOJ-2314

题目大意

多组数据,第一行为数据组数 \(T\)。

对于每一组数据,第一行为 \(n,m\) 表示 \(n\) 个结点,\(m\) 条有向边。

接下来 \(m\) 行,每一行有四个正整数 \(i,j,l_{ij},c_{ij}\) ,表示有一条从\(i\)到\(j\)的有向边,要求正整数流量 \(f_{ij} \in [l_{ij},c_{ij}]\) 。

题目还提到,不存在自环;以及如果存在 \(i\) 到 \(j\) 的边,则不存在 \(j\) 到 \(i\) 的反向边。

如果有解输出 \(YES\) ,并按顺序输出每一条边的可行流 \(f_k\) ,否则输出 \(NO\) 。

题目解析

题目为无源汇有上下界的可行流模板。

要点在于:

将每一条边用其 下界流 填满,算出每条边的剩余容量 \(cap_{ij} = c_{ij}-l_{ij}\) 以及每个结点的流量盈余 (\(R[x] = out_{\sum {l_{x*}}} - in_{\sum {l_{*x}}}\))。

新设置两个点——超级源点 \(s\) 和超级汇点 \(t\)。

对于结点 \(x\),如果盈余为正,连接 \(s\rightarrow x\) ;如果盈余为负,连接 \(x\rightarrow t\) ,容量为\(|R[x]|\)。(这是本题的关键所在,为什么可以这样等效?)

对于新图,跑最大流即可。(本题解用的是\(ISAP\),用\(Dinic\)当然也可以啦。)

如果发现源点\(s\)出发的边不是满流(\(\exists i, cap_{si} > flow_{si}\)),则证明原图可行流不存在。

否则可以得到答案(\(f_{ij} = l_{ij} + flow_{ij}\))。

例如:

Sample Input

4 6

1 2 1 2

2 3 1 2

3 4 1 2

4 1 1 2

1 3 1 2

4 2 1 2

可以化作下图。

算出边的剩余容量 \(cap_{ij}\) (以黑色数字标注在边上)和结点的流量盈余 \(R[x]\) (标注在点上,红色为正,蓝色为负)。

然后连结超级源点 \(s\) 和超级汇点 \(t\) 。

通过这种方法可以转化成一般的最大流问题。

这样做为什么正确呢?

其实可以形象化地理解,设置源点 \(s\) 和汇点 \(t\) 是两个虚拟结点。

对于结点 \(x\),为了保证除了源汇两点以外的点流量守恒,即 \(out_{\sum {l_{x*}}} = in_{\sum {l_{*x}}}\) 。

如果 \(R[x]>0\) ,盈余为正,可以看作这部分的盈余是从源点 \(s\) 流入的,所以连接 \(s\rightarrow x\) ;

如果 \(R[x]<0\) ,发现“入不敷出”(盈余为负),可以看作这部分的亏损是流入汇点 \(t\) 导致的,所以连接 \(x\rightarrow t\) 。

最后跑完最大流,则检查这些虚拟的边是否“满流”。

如果不能满流,则说明盈余来自源点/亏损流向汇点的假设不能成立,存在无法满足流量守恒的结点,该网络图自然不存在可行流。

如果能够满流,则说明这样假设是能够成立的,网络中的流量就是可行流。

由于虚拟的源汇依然有出流=入流,因此只要检查从源点 \(s\) 流出的边(或者流出汇点 \(t\) 的边)是否满流即可。

参考代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 255;
const int INF = 2147483647;
struct Edge{
int from, to, cap, flow, min;
};
int n, m, s, t, gap[N], cur[N], dep[N], R[N];
vector <Edge> e;
vector <int> G[N]; void init()
{
memset(gap, 0, sizeof gap);
memset(cur, 0, sizeof cur);
memset(dep, 0, sizeof dep);
++gap[dep[t] = 1];
queue <int> Q;
Q.push(t);
while (!Q.empty()) {
int x=Q.front(); Q.pop();
for (int i = 0; i < G[x].size(); i++)
{
int v = e[G[x][i]].to;
if (!dep[v])
{
++gap[dep[v] = dep[x]+1];
Q.push(v);
}
}
}
}
int augment(int x, int a)
{
if (x == t || !a) return a;
int flow = 0;
for (int &i=cur[x]; i < G[x].size(); i++)
{
Edge& b = e[G[x][i]];
if (dep[x] == dep[b.to] + 1 && b.cap > b.flow) {
int tmp = augment(b.to, min(a, b.cap - b.flow));
flow += tmp;
a -= tmp;
b.flow += tmp;
e[G[x][i]^1].flow -= tmp;
if (!a) return flow;
}
}
if (!(--gap[dep[x]])) dep[s] = n+1;
++gap[++dep[x]], cur[x] = 0;
return flow;
}
ll maxFlow()
{
init();
ll ans = 0;
while (dep[s] <= n) ans += augment(s, INF);
for (int i = 0; i < G[s].size(); ++i) {
if (e[G[s][i]].cap > e[G[s][i]].flow) return -1;
}
return ans;
}
void addEdge(int u, int v, int l, int c, int i)
{
e.push_back((Edge){u, v, c-l, 0, l});
e.push_back((Edge){v, u, 0, 0, 0});
G[u].push_back(i);
G[v].push_back(i^1);
R[u] -= l;
R[v] += l;
}
void Clear()
{
e.clear();
for (int i = 0; i <= n; ++i) G[i].clear();
memset(R, 0, sizeof R);
n = m = s = t = 0;
}
int main()
{
int T;
scanf("%d", &T);
for (int Kase=0; Kase<T; ++Kase)
{
if (Kase) {Clear(); putchar('\n');}
scanf("%d%d", &n, &m);
for (int i = 0; i < m; ++i) {
int u, v, l ,c;
scanf("%d%d%d%d", &u, &v, &l, &c);
addEdge(u, v, l, c, i << 1);
}
s = ++n, t = ++n;
int j = m-1;
for (int i = 1; i <= n; ++i) {
if (R[i] > 0) addEdge(s, i, 0, R[i], (++j) << 1);
else if (R[i] < 0) addEdge(i, t, 0, -R[i], (++j) << 1);
}
ll a = maxFlow(); // printf("maxflow = %lld\n", a);
// for (int i = 0; i <= j; ++i) {
// printf("%d -> %d (%d/%d)\n", e[i << 1].from, e[i << 1].to, e[i << 1].flow, e[i << 1].cap);
// } //这一部分查看可以看新图的流量情况 if (a == -1) {printf("NO\n"); continue;}
printf("YES\n");
for (int i = 0; i < m; ++i)
printf("%d\n", e[i << 1].flow+e[i << 1].min);
}
return 0;
}

感谢支持!

【模板】无源汇有上下界可行流(网络流)/ZOJ2314的更多相关文章

  1. [loj#115] 无源汇有上下界可行流 网络流

    #115. 无源汇有上下界可行流 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据   题 ...

  2. LOJ.115.[模板]无源汇有上下界可行流(Dinic)

    题目链接 参考:http://blog.csdn.net/clove_unique/article/details/54884437 http://blog.csdn.net/wu_tongtong/ ...

  3. 2018.08.20 loj#115. 无源汇有上下界可行流(模板)

    传送门 又get到一个新技能,好兴奋的说啊. 一道无源汇有上下界可行流的模板题. 其实这东西也不难,就是将下界变形而已. 准确来说,就是对于每个点,我们算出会从它那里强制流入与流出的流量,然后与超级源 ...

  4. 【LOJ115】无源汇有上下界可行流(模板题)

    点此看题面 大致题意: 给你每条边的流量上下界,让你判断是否存在可行流.若有,则还需输出一个合法方案. 大致思路 首先,每条边既然有一个流量下界\(lower\),我们就强制它初始流量为\(lower ...

  5. loj#115. 无源汇有上下界可行流

    \(\color{#0066ff}{ 题目描述 }\) 这是一道模板题. \(n\) 个点,\(m\) 条边,每条边 \(e\) 有一个流量下界 \(\text{lower}(e)\) 和流量上界 \ ...

  6. Zoj 2314 Reactor Cooling(无源汇有上下界可行流)

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1314 题意:    给n个点,及m根pipe,每根pipe用来流躺液体的,单向 ...

  7. LOJ [#115. 无源汇有上下界可行流](https://loj.ac/problem/115)

    #115. 无源汇有上下界可行流 先扔个板子,上下界的东西一点点搞,写在奇怪的合集里面 Code: #include <cstdio> #include <cstring> # ...

  8. LibreOJ #115. 无源汇有上下界可行流

    二次联通门 : LibreOJ #115. 无源汇有上下界可行流 /* LibreOJ #115. 无源汇有上下界可行流 板子题 我也就会写写板子题了.. */ #include <cstdio ...

  9. 无源汇有上下界可行流(ZQU 1590)

    无源汇有上下界可行流(也就是循环流) 模型:一个网络,求出一个流,使得每条边的流量必须>=Li且<=Hi, 每个点必须满足总流入量=总流出量(流量守恒)(这个流的特点是循环往复,无始无终) ...

随机推荐

  1. camera HSYNC:VSYNC

    HSYNC:行锁存,换行信号VSYNC:祯锁存,换页信号 320×240的屏,每一行需要输入320个脉冲来依次移位.锁存进一行的数据,然后来个HSYNC 脉冲换一行:这样依次输入240行之后换行同时来 ...

  2. Java并发:ReadWriteLock 读写锁

    读写锁在同一时刻可以允许多个线程访问,但是在写线程访问,所有的读线程和其他写线程均被阻塞. 读写锁不像 ReentrantLock 那些排它锁只允许在同一时刻只允许一个线程进行访问,读写锁可以允许多个 ...

  3. shell 匿名管道和命名管道

    管道的特点:如果管道中没有数据,那么取管道数据的操作就会滞留,直到管道内进入数据,然后读出后才会终止这一操作:同理,写入管道的操作如果没有读取管道的操作,这一动作也会滞留. 1,匿名管道 匿名管道使用 ...

  4. (一)Mongodb学习之 Centos 7 单机部署

    学习参考:https://www.runoob.com/mongodb/mongodb-tutorial.html 一.部署环境 1.系统:Centos 7 2.mongodb: mongodb-li ...

  5. Downward API —— 在容器内部获取 Pod 信息

    我们知道,每个 Pod 在被超过创建出来之后,都会被系统分配唯一的名字.IP地址,并且处于某个 Namespace 中,那么我们如何在 Pod 的容器内获取 Pod 的这些重要信息呢? 答案就是使用 ...

  6. The art of multipropcessor programming 读书笔记-3. 自旋锁与争用(2)

    本系列是 The art of multipropcessor programming 的读书笔记,在原版图书的基础上,结合 OpenJDK 11 以上的版本的代码进行理解和实现.并根据个人的查资料以 ...

  7. php swoft redis 发布和订阅

    //订阅 public function subscribe() { /* @var \Swoft\Redis\Redis $redis */ $redis = App::getBean(\Swoft ...

  8. 【Go语言细节】反射

    什么是反射 维基百科上反射的定义: 在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问.检测和修改它本身状态或行为的一种能力.用比喻来说,反射就是程序在运行的时候能够"观 ...

  9. 这一篇 K8S(Kubernetes)集群部署 我觉得还可以!!!

    点赞再看,养成习惯,微信搜索[牧小农]关注我获取更多资讯,风里雨里,小农等你,很高兴能够成为你的朋友. 国内安装K8S的四种途径 Kubernetes 的安装其实并不复杂,因为Kubernetes 属 ...

  10. k8s入坑之路(10)kubernetes coredns详解

    概述 作为服务发现机制的基本功能,在集群内需要能够通过服务名对服务进行访问,那么就需要一个集群范围内的DNS服务来完成从服务名到ClusterIP的解析. DNS服务在kubernetes中经历了三个 ...