无源汇有上下界可行流(ZQU 1590)
无源汇有上下界可行流(也就是循环流)
模型:一个网络,求出一个流,使得每条边的流量必须>=Li且<=Hi,
每个点必须满足总流入量=总流出量(流量守恒)(这个流的特点是循环往复,无始无终)
可行流算法的核心是将一个不满足流量守恒的初始流调整成满足流量守恒的流
流量守恒,即每个点的总流入量=总流出量
如果存在一个可行流,那么一定满足每条边的流量都大于等于流量的下限
因此我们可以令每条边的流量等于流量下限,得到一个初始流,然后建出这个流的残量网络
(即:每条边的流量等于这条边的流量上限与流量下限之差)
这个初始流不一定满足流量守恒,因此最终的可行流一定是在这个初始流的基础上增大了一些边的流量使得所有点满足流量守恒
因此我们考虑在残量网络上求出一个另不满足流量守恒的附加流,
使得这个附加流和我们的初始流合并之后满足流量守恒
那么首先我们需要开一个数组A,A[i]表示i在初始流中的流入量-流出量的值
那么A[i]的正负表示流入量和流出量的大小关系,
A[i]>0,说明附加流的流入量要小于流出量
A[i]<0,说明附加流的流入量要大于流出量
所以A[i]=附加流流出量-流入量
下面就用A[i]表示初始流中i的流入量-流出量
但是dinic算法能够求的是满足流量守恒的有源汇最大流,
不能在原网络上直接求一个这样的无源汇且不满足流量守恒的附加流
注意到附加流是在原网络上不满足流量守恒的,这启发我们添加一些原网络之外的边和点,
用这些边和点实现“原网络上流量不守恒”的限制
具体地,如果一个点i在原网络上的附加流中需要满足流入量>流出量(A[i]<0),
那么我们需要给多的流入量找一个去处,因此我们建一条从i出发流量=|A[i]|的边
如果A[i]>0,也就是我们需要让附加流中的流出量>流入量,我们需要让多的流出量有一个来路,
因此我们建一条指向i的流量=|A[i]|的边.
当然,我们所新建的从i出发的边也要有个去处,指向i的边也要有个来路,
因此我们新建一个虚拟源点ss和一个虚拟汇点tt
(双写字母是为了和有源汇网络流中的源点s汇点t相区分)
新建的指向i的边都从ss出发,从i出发的边都指向tt
一个点要么有一条边指向tt,要么有一条边来自ss,
指向tt的边的总流量上限一定等于ss流出的边的总流量上限
因为每一条边对两个点的A[i]贡献一正一负大小相等,所以全部点的A[i]之和等于0,
即小于0的A[i]之和的绝对值=大于0的A[i]之和的绝对值.
如果我们能找到一个流满足新加的边都满流,这个流在原图上的部分就是我们需要的附加流
那么怎样找出一个新加的边都满流的流呢?
可以发现假如存在这样的方案,这样的流一定是我们所建出的图的ss-tt最大流,
所以跑ss到tt的最大流即可
如果最大流的大小等于ss出发的所有边的流量上限之和,则存在这样的附加流满足题意
最后,每条边在可行流中的流量=容量下界+附加流中它的流量(即跑完dinic之后所加反向边的权值)
————————————————
版权声明:本文为CSDN博主「Coco_T_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wu_tongtong/article/details/73320968
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
using namespace std;
const int maxn=;
const int inf=0x3f3f3f3f;
int head[maxn],level[maxn]; //前者为邻接表必要数据,后者为dinic的层 数据
int in[maxn]; //一条边的初始流量(最低值 也就是定为下界)
int limit[maxn]; //limit为该点的流量 小于0的时候是流出多
int bh[maxn]; //一条边的反向边的流量(正向边流出了多少,反向边就是多少)
//所以用初始的下界流量+上这个方向边的流量就是最终答案;
//那么为什么不直接正向呢???
//废话 正向求比较麻烦嘛。 原本的值是可以流的量,正向边流出去后
//那么答案就是可以流的量减去剩余的量就是答案;
//所以还不如直接求反向呢
int num; //邻接表
void init()
{
num=- ;
memset(head,-,sizeof(head));
}
struct node
{
int v,w,next;
}G[];
int bfs(int s,int t)
{
queue<int>q;
q.push(s);
memset(level,-,sizeof(level));
level[s]=;
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i!=-;i=G[i].next){
int v=G[i].v;
if(G[i].w>&&level[v]==-){
level[v]=level[u]+;
q.push(v);
}
}
}
return level[t];
}
int dfs(int s,int t,int f)
{
if(s==t) return f;
int ans=;
for(int i=head[s];i!=-;i=G[i].next){
int v=G[i].v;
if(G[i].w>&&level[s]+==level[v]){
int d=dfs(v,t,min(G[i].w,f-ans));
if(d>){
G[i].w-=d;
G[i^].w+=d;
ans+=d;
if(ans==f) return ans;
}
}
}
return ans;
}
int dinic(int s,int t)
{
int ans=;
while(){
int temp=bfs(s,t);
if(temp==-) break;
ans+=dfs(s,t,inf);
}
return ans;
}
void build(int u,int v,int w)
{
num++;
G[num].v=v;
G[num].w=w;
G[num].next=head[u];
head[u]=num; num++;
G[num].v=u;
G[num].w=;
G[num].next=head[v];
head[v]=num;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int s=;
int t=n+;
init();
for(int i=;i<=m;i++){
int u,v,w1,w2;
scanf("%d%d%d%d",&u,&v,&w1,&w2);
in[i]=w1; //一开始这条边的流量
limit[v]+=w1; //v这个点的流入,增加
limit[u]-=w1; //u这个点的流出,减少
build(u,v,w2-w1); //剩下的可以操作的流量拿来建边
bh[i]=num; //标记这条边的反向边的num
}
int sout=;
for(int i=;i<=n;i++){
//如果流入比较大,那么从源点向其建边;流量就为这个点的流量;
if(limit[i]>) build(s,i,limit[i]),sout+=limit[i];
if(limit[i]<) build(i,t,-limit[i]);
//如果流出比较大,那么从这个点向汇点建边,流量为这个点的流量的绝对值;
}
int ans=dinic(s,t);
//只有当流入汇点的流量等于流入这个图的流量,才是有解;
if(ans==sout){
printf("YES\n");
for(int i=;i<=m;i++)
printf("%d\n",in[i]+G[bh[i]].w);
}
else printf("NO\n");
return ;
}
无源汇有上下界可行流(ZQU 1590)的更多相关文章
- LOJ [#115. 无源汇有上下界可行流](https://loj.ac/problem/115)
#115. 无源汇有上下界可行流 先扔个板子,上下界的东西一点点搞,写在奇怪的合集里面 Code: #include <cstdio> #include <cstring> # ...
- 2018.08.20 loj#115. 无源汇有上下界可行流(模板)
传送门 又get到一个新技能,好兴奋的说啊. 一道无源汇有上下界可行流的模板题. 其实这东西也不难,就是将下界变形而已. 准确来说,就是对于每个点,我们算出会从它那里强制流入与流出的流量,然后与超级源 ...
- [loj#115] 无源汇有上下界可行流 网络流
#115. 无源汇有上下界可行流 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 题 ...
- loj#115. 无源汇有上下界可行流
\(\color{#0066ff}{ 题目描述 }\) 这是一道模板题. \(n\) 个点,\(m\) 条边,每条边 \(e\) 有一个流量下界 \(\text{lower}(e)\) 和流量上界 \ ...
- 【LOJ115】无源汇有上下界可行流(模板题)
点此看题面 大致题意: 给你每条边的流量上下界,让你判断是否存在可行流.若有,则还需输出一个合法方案. 大致思路 首先,每条边既然有一个流量下界\(lower\),我们就强制它初始流量为\(lower ...
- Zoj 2314 Reactor Cooling(无源汇有上下界可行流)
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1314 题意: 给n个点,及m根pipe,每根pipe用来流躺液体的,单向 ...
- LibreOJ #115. 无源汇有上下界可行流
二次联通门 : LibreOJ #115. 无源汇有上下界可行流 /* LibreOJ #115. 无源汇有上下界可行流 板子题 我也就会写写板子题了.. */ #include <cstdio ...
- 【模板】无源汇有上下界可行流(网络流)/ZOJ2314
先导知识 网络最大流 题目链接 https://vjudge.net/problem/ZOJ-2314 题目大意 多组数据,第一行为数据组数 \(T\). 对于每一组数据,第一行为 \(n,m\) 表 ...
- ZOJ 2314 Reactor Cooling(无源汇有上下界可行流)
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2314 题目大意: 给n个点,及m根pipe,每根pipe用来流躺 ...
随机推荐
- If no other git process is currently running, this probably means a git proc
原因:用SourceTree提交代码,发现这个问题.好像是因为上个进程没停止,造成文件不识别 解决:把仓库目录里的.git/index.lock文件(文件是隐藏的)删除就可以了.删除index.loc ...
- MongoDB geonear和文本命令驱动程序2.0
文本查询,q作为查询字符串: coll.FindAsync<Foo>(Builders<Foo>.Filter.Text(q)); 文本查询需要一个文本索引.要从C#创建代码, ...
- PP: DeepAR: probabilistic forecasting with autoregressive recurrent networks
FROM Amazon research Germany PROBLEM probabilistic forecasting: estimate the probability distributio ...
- Eclipse的使用配置
Eclipse 是一个开放源代码的.基于Java的可扩展开发平台.目前许多开发者开发时仍会选择使用Eclipse,很多初学者刚开始接触Java也是从使用Eclipse开始的.本篇博客主要介绍Eclip ...
- DOM增删改
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...
- macOS系统下安装ChromeDriver
1.对应的chrome浏览器需要安装对应的驱动,对应列表如下: chromedriver版本 支持的chrome版本 v2.43 v69-71 v2.42 v68-70 v2.41 v ...
- Docker(一)概念与基础
Docker 基础 为什么需要docker?在传统部署下,我们会遇到不同机器.不同依赖版本的兼容性等问题,解决此问题一般会消耗大量时间,并且在不同机器上均要执行统一环境的部署也是一个耗时较长的工作.除 ...
- 函数的应用_python
一.各类函数应用 1.高阶函数:函数里面调用函数 例子: def add(a): return (a*a) def print_info(fun,c,d): #传入函数与参数 return fun(c ...
- layer iframe 设置关闭按钮 和刷新和弹出框设置
layer弹出层的关闭问题 就是在执行添加或修改的时候,需要将数据提交到后台进行处理,这时候添加成功之后最理想的状态是关闭弹出层并且刷新列表的数据信息,之前一直想实现这样,可一直没有成功,今天决定 ...
- how to activate XMind8 to pro version.
From activate Xmind 8. in step 3: run ./setup.sh in sudo command, and use the following command to r ...