这道题跟求最大流的时候差不多。

都是先构造可行流,然后判断是否可行,

可行的话,就利用残余流量,构造从汇点t跑到源点s的最大流,

如何求出答案呢。

在第一次求可行流的dinic后,跟求最大流的时候一样,从t到s是可行流的流量;

这个时候t到s的反向边,也就是s到t的流量就是t到s流的量(因为t到s定义权值为inf,要从这条边算出来,得用inf去减到这条边剩下的才是答案,有点麻烦)

所以反向边是个便捷的求法。

所以在第一次dinic之后,t到s的反向便的流量就是可行流的流量;

然后我们再从t到s跑最大流,看最大能跑掉多少,就是最后的答案。 (这里肯定不会影响可行流!,因为已经在第一次dinic的时候保证了可行(即sum==tmpp))

求第二次dinic的时候,要将s跟t之间的边给去掉。

 #include<cstdio>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
using namespace std;
typedef long long ll;
const ll maxn=;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll vis[maxn];
ll head[maxn],level[maxn]; //前者为邻接表必要数据,后者为dinic的层 数据
ll in[maxn]; //一条边的初始流量(最低值 也就是定为下界)
ll limit[maxn]; //limit为该点的流量 小于0的时候是流出多
//ll bh[maxn]; //一条边的反向边的流量(正向边流出了多少,反向边就是多少)
//所以用初始的下界流量+上这个方向边的流量就是最终答案;
//那么为什么不直接正向呢???
//废话 正向求比较麻烦嘛。 原本的值是可以流的量,正向边流出去后
//那么答案就是可以流的量减去剩余的量就是答案;
//所以还不如直接求反向呢
ll num; //邻接表
void init()
{
num=- ;
memset(head,-,sizeof(head));
}
struct node
{
ll v,w,next;
}G[maxn*];
ll bfs(ll s,ll t)
{
queue<ll>q;
q.push(s);
memset(level,-,sizeof(level));
level[s]=;
while(!q.empty()){
ll u=q.front();
q.pop();
for(ll i=head[u];i!=-;i=G[i].next){
ll v=G[i].v;
if(G[i].w>&&level[v]==-){
level[v]=level[u]+;
q.push(v);
}
}
}
return level[t];
}
ll dfs(ll s,ll t,ll f)
{
if(s==t) return f;
ll ans=;
for(ll i=vis[s];i!=-;i=G[i].next){
vis[s]=i; //当前弧优化
ll v=G[i].v;
if(G[i].w>&&level[s]+==level[v]){
ll 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;
}
}
}
// if(ans==0) level[s]=0;
return ans;
}
ll dinic(ll s,ll t)
{
ll ans=;
while(){
ll temp=bfs(s,t);
if(temp==-) break;
memcpy(vis,head,sizeof(head));
ans+=dfs(s,t,inf);
}
return ans;
}
void build(ll u,ll v,ll 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()
{
init();
ll n,m,s,t;
scanf("%lld%lld%lld%lld",&n,&m,&s,&t);
for(ll i=;i<=m;i++){
ll u,v,w1,w2;
scanf("%lld%lld%lld%lld",&u,&v,&w1,&w2);
// in[u]=w1;
limit[u]-=w1;
limit[v]+=w1;
build(u,v,w2-w1);
}
ll S=;ll T=n+;
ll sum=;
for(ll i=;i<=n;i++){
if(limit[i]<) build(i,T,-limit[i]);
if(limit[i]>) build(S,i,limit[i]),sum+=limit[i];
}
build(t,s,inf);
//其实这里应该有上面的limit的变化 只是因为这里的w1为0,所以省略不写。
ll tmpp=dinic(S,T);
if(tmpp!=sum) printf("please go home to sleep\n");
else{
ll tmp1=G[num].w;
G[num].w=G[num-].w=;
ll tmp2=dinic(t,s);
printf("%lld\n",tmp1-tmp2);
}
return ;
}

有源汇有上下界最小流 (ZQU 1592)的更多相关文章

  1. loj #117. 有源汇有上下界最小流

    题目链接 有源汇有上下界最小流,->上下界网络流 注意细节,边数组也要算上后加到SS,TT边. #include<cstdio> #include<algorithm> ...

  2. LOJ.117.[模板]有源汇有上下界最小流(Dinic)

    题目链接 有源汇有上下界最小流 Sol1. 首先和无源汇网络流一样建图,求SS->TT最大流: 然后连边(T->S,[0,INF]),再求一遍SS->TT最大流,答案为新添加边的流量 ...

  3. sgu 176 Flow construction(有源汇的上下界最小流)

    [题目链接] http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=11025 [模型] 有源汇点的上下界最小流.即既满足上下界又满足 ...

  4. Flow construction SGU - 176 有源汇有上下界最小流 二分法和回流法

    /** 题目:Flow construction SGU - 176 链接:https://vjudge.net/problem/SGU-176 题意: 有源汇有上下界的最小流. 给定n个点,m个管道 ...

  5. 【 POJ - 3801】Crazy Circuits(有源汇、上下界最小流)

    Description You’ve just built a circuit board for your new robot, and now you need to power it. Your ...

  6. bzoj 2502 清理雪道(有源汇的上下界最小流)

    [题意] 有一个DAG,要求每条边必须经过一次,求最少经过次数. [思路] 有上下界的最小流.  边的下界为1,上界为无穷.构造可行流模型,先不加ts边跑一遍最大流,然后加上t->s的inf边跑 ...

  7. sgu176 Flow Construction【有源汇有上下界最小流】

    同样是模板题. 首先将有源汇转换为无源汇,假设原来的源汇为st,我们加入的源汇为ST,那么我们应该从t到s连一条流量为+∞的边,使原来的st满足收支平衡,退化为普通节点. 分离必要边和其他边,从S到T ...

  8. Crazy Circuits HDU - 3157(有源汇有上下界最小流)

    给出每条边的下界 求最小流 板题 提供两个板子代码 虽然这个题 第一个比较快 但在loj上https://loj.ac/problem/117 的板题  第一个1700+ms 第二个才600+ms   ...

  9. LOJ117 有源汇有上下界最小流(上下界网络流)

    跑出可行流后从原来的汇点向原来的源点跑最大流,原图最小流=inf-maxflow.显然超源超汇的相关边对其也没有影响.原图最小流=可行流-原图新增流量,因为t向s流量增加相当于s向t流量减少.但为什么 ...

  10. 有源汇有上下界最小流 DInic + 各种优化 模板

    例题:loj117 : https://loj.ac/problem/117 //其实就是判断可行流后倒着求一遍最大流 #include <iostream> #include <c ...

随机推荐

  1. meet in the middle 折半搜索 刷题记录

    复杂度分析 假设本来是n层,本来复杂度是O(2^n),如果meet in middle那就是n/2层,那复杂度变为O( 2^(n/2) ),跟原来的复杂度相比就相当于开了个方 比如如果n=40那爆搜2 ...

  2. mysql-使用存储过程创建大批量数据

    参考:https://www.iteye.com/blog/825635381-2161290 场景1.创建1万个table,每个table种插入1条记录 DELIMITER $$ CREATE DA ...

  3. vue配置开发,测试,生产环境api

    npm run build 调用开发环境接口,打包开发环境npm run build:test 调用测试环境接口,打包测试环境npm run build:prod 调用生产环境接口,打包生产环境 vu ...

  4. Python 之路Day13

    匿名函数 一行函数 lambda == def -- 关键字 lambda x:x x 是普通函数的形参(位置,关键字……)可以不接收参数,可以不写 :x 是普通函数的函数值(只能返回一个数据类型), ...

  5. Selenium3+python自动化012-测试用例模块化

    测试用例模块化特点:为po模型做准备. 1.提取公共方法. 2.提取数据. 3.提取逻辑. # @Author:lsj # @version V1.0 # -*- coding:UTF-8 -*- i ...

  6. Linux内核0.11代码阅读(转)

    最近决定开始阅读Linux 0.11的源代码. 学习Linux操作系统的核心概念最好的方法莫过于阅读源代码.而Linux当前最新的源代码包已经有70MB左右,代码十分庞大,要想深入阅读十分困难.而Li ...

  7. Java基础面试题总结二

    1,什么是字符串常量池? 字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价.JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化.为 了减少在JVM中创建的字符串的数量 ...

  8. Linux下Libevent安装和简单实用

    前言 Libevent 是一个用C语言编写的.轻量级的开源高性能事件通知库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大:源代码相 ...

  9. 获取 Android APP 版本信息工具类(转载)

    获取 Android APP 版本信息工具类 获取手机APP版本信息工具类 1.获取版本名称 2.获取版本号 3.获取App的名称 package com.mingyue.nanshuibeidiao ...

  10. MyBatis-单表的增删改查(CRUD)操作

          在学习MyBatis的单表的增删改查操作之前,还是再次熟悉下MyBatis这个框架,只有对其熟悉的情况下,才能很好的使用,灵活的开发.         MyBatis优点:         ...