/**

题目:Flow construction SGU - 176
链接:https://vjudge.net/problem/SGU-176
题意:
有源汇有上下界的最小流。
给定n个点,m个管道。每个管道给出u,v,z,c。u表示起点,v表示终点,z表示容量,如果c==1,那么表示还有下界为z。
如果c==0,表示没有下界。
求从1到n的最小流。
思路:
第一种做法:
转化为无源汇求超级源S到超级汇T的最大流flow1(此时从s出发的流和为flow1),然后讲t到s的边删掉(可以使流量等于容量,这样求t到s的最大流就不会经过他了。)
求t到s的最大流flow2(从s出发的流减少的量).是为了回流,因为原先求flow1的过程,是为了满足下界的可行流。这个在原图的可行流可能可以变得更小,通过回流使其缩小。
求t到s的最大流并不会影响原来附加边的流量。所以保证了是下界满足的可行流。
然后用flow1-flow2就是结果。 第二种做法:
构造无源汇有上下界的可行流做法,只不过t到s的边的上下界要改一下。
二分t到s的上界a,下界为0,如果是可行流最小的a便是最小流。如果是求最大流,那么就是二分t到s的下界a,上界无穷,如果是可行流,那么最大的a便是最大流。
不懂的看文档解释。https://wenku.baidu.com/view/0f3b691c59eef8c75fbfb35c.html 关于每次二分,处理一次最大流,那么下次在计算最大流的时候,难道又要重新建图?
反正是结构体存的,新加一个变量存储。下次直接从这个变量获取即可。注意t到s这条边的修改。或者最后面再加进去。 */ 第一种做法 #include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int N = ;///n+m=1365
int in[N];
int out[N];
struct Edge{
int from, to, cap, flow;
Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
struct Dinic{
int n, m, s, t;
vector<Edge> edges;
vector<int> G[N];
bool vis[N];
int d[N];
int cur[N]; void init(int n)
{
this->n = n;
for(int i = ; i <= n; i++) G[i].clear();
edges.clear();
} void AddEdge(int from,int to,int cap)
{
edges.push_back(Edge(from,to,cap,));
edges.push_back(Edge(to,from,,));
m = edges.size();
G[from].push_back(m-);
G[to].push_back(m-);
} bool BFS()
{
memset(vis, , sizeof vis);
queue<int> Q;
Q.push(s);
d[s] = ;
vis[s] = ;
while(!Q.empty())
{
int x = Q.front();
Q.pop();
for(int i = ; i < G[x].size(); i++)
{
Edge &e = edges[G[x][i]];
if(!vis[e.to]&&e.cap>e.flow)
{
vis[e.to] = ;
d[e.to] = d[x]+;
Q.push(e.to);
}
}
}
return vis[t];
} int DFS(int x,int a)
{
if(x==t||a==) return a;
int flow = , f;
for(int &i = cur[x]; i < G[x].size(); i++)
{
Edge& e = edges[G[x][i]];
if(d[x]+==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>)
{
e.flow += f;
edges[G[x][i]^].flow -= f;
flow += f;
a -= f;
if(a==) break;
}
}
return flow;
} int Maxflow(int s,int t)
{
this->s = s, this->t = t;
int flow = ;
while(BFS())
{
memset(cur, , sizeof cur);
flow += DFS(s,INF);
}
return flow;
}
};
int dw[N*N];
int main()
{
int n, m;
while(scanf("%d%d",&n,&m)==)
{
Dinic dinic;
dinic.init(n+);
int u, v, cap, flag;///1,n为普通源汇。
int s = , t = n+;///超级源汇。
memset(dw, , sizeof dw);
memset(in, , sizeof in);
memset(out, , sizeof out);
for(int i = ; i<m; i++){
scanf("%d%d%d%d",&u,&v,&cap,&flag);
if(flag==){
dw[i] = cap;
dinic.AddEdge(u,v,);
out[u]+=cap;
in[v]+=cap;
}else
{
dinic.AddEdge(u,v,cap); }
}
int ts;
dinic.AddEdge(n,,INF);
ts = dinic.edges.size()-;
int sum = ;
for(int i = ; i <= n; i++){
if(in[i]>out[i]){
dinic.AddEdge(s,i,in[i]-out[i]);
sum += in[i]-out[i];
}
if(in[i]<out[i]){
dinic.AddEdge(i,t,out[i]-in[i]);
}
}
int flow = dinic.Maxflow(s,t);
if(flow!=sum){
printf("Impossible\n"); continue;
}
dinic.edges[ts].cap = dinic.edges[ts].flow;///使其求n到1的最大流无法经过。
int flow2 = dinic.Maxflow(n,);///回流
printf("%d\n",flow-flow2);
for(int i = ; i < m; i++){
if(i==m-){
printf("%d\n",dinic.edges[*i].flow+dw[i]);
}else
{
printf("%d ",dinic.edges[*i].flow+dw[i]);
}
}
}
return ;
} 第二种做法 #include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int N = ;///n+m=1365
int in[N];
int out[N];
struct Edge{
int from, to, cap, flow;
Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
struct Dinic{
int n, m, s, t;
vector<Edge> edges;
vector<int> G[N];
bool vis[N];
int d[N];
int cur[N]; void init(int n)
{
this->n = n;
for(int i = ; i <= n; i++) G[i].clear();
edges.clear();
} void AddEdge(int from,int to,int cap)
{
edges.push_back(Edge(from,to,cap,));
edges.push_back(Edge(to,from,,));
m = edges.size();
G[from].push_back(m-);
G[to].push_back(m-);
} bool BFS()
{
memset(vis, , sizeof vis);
queue<int> Q;
Q.push(s);
d[s] = ;
vis[s] = ;
while(!Q.empty())
{
int x = Q.front();
Q.pop();
for(int i = ; i < G[x].size(); i++)
{
Edge &e = edges[G[x][i]];
if(!vis[e.to]&&e.cap>e.flow)
{
vis[e.to] = ;
d[e.to] = d[x]+;
Q.push(e.to);
}
}
}
return vis[t];
} int DFS(int x,int a)
{
if(x==t||a==) return a;
int flow = , f;
for(int &i = cur[x]; i < G[x].size(); i++)
{
Edge& e = edges[G[x][i]];
if(d[x]+==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>)
{
e.flow += f;
edges[G[x][i]^].flow -= f;
flow += f;
a -= f;
if(a==) break;
}
}
return flow;
} int Maxflow(int s,int t)
{
this->s = s, this->t = t;
int flow = ;
while(BFS())
{
memset(cur, , sizeof cur);
flow += DFS(s,INF);
}
return flow;
}
};
int dw[N*N];
int main()
{
int n, m;
while(scanf("%d%d",&n,&m)==)
{
Dinic dinic;
dinic.init(n+);
int u, v, cap, flag;///1,n为普通源汇。
int s = , t = n+;///超级源汇。
memset(dw, , sizeof dw);
memset(in, , sizeof in);
memset(out, , sizeof out);
for(int i = ; i<m; i++){
scanf("%d%d%d%d",&u,&v,&cap,&flag);
if(flag==){
dw[i] = cap;
dinic.AddEdge(u,v,);
out[u]+=cap;
in[v]+=cap;
}else
{
dinic.AddEdge(u,v,cap); }
}
int sum = ;
for(int i = ; i <= n; i++){
if(in[i]>out[i]){
dinic.AddEdge(s,i,in[i]-out[i]);
sum += in[i]-out[i];
}
if(in[i]<out[i]){
dinic.AddEdge(i,t,out[i]-in[i]);
}
}
Dinic Tdinic = dinic;
int flow;
int lo = , hi = INF, mid;
while(lo<hi){///最小流,二分上界,取最小值。
mid = (lo+hi)/;
dinic = Tdinic;
dinic.AddEdge(n,,mid);
flow = dinic.Maxflow(s,t);
if(flow!=sum){
lo = mid+;
}else
{
hi = mid;
}
}
if(hi==lo){
printf("Impossible\n"); continue;
}
printf("%d\n",hi);
dinic = Tdinic;///注意复原,因为此时的dinic不是最小流为hi的时候的。要重新计算。
dinic.AddEdge(n,,hi);
dinic.Maxflow(s,t);
for(int i = ; i < m; i++){
if(i==m-){
printf("%d\n",dinic.edges[*i].flow+dw[i]);
}else
{
printf("%d ",dinic.edges[*i].flow+dw[i]);
}
}
}
return ;
}

Flow construction SGU - 176 有源汇有上下界最小流 二分法和回流法的更多相关文章

  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. sgu176 Flow Construction【有源汇有上下界最小流】

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

  5. sgu 176 有源汇有上下界的最小流模板题

    /*参考博文:http://hi.baidu.com/dragon_eric123/item/82e259200ece744046996282 有上下界的有源最小流 */ #include<st ...

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

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

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

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

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

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

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

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

随机推荐

  1. IT词汇表

    本人采集到了数十万篇中文技术类博客,进行分词后根据出现的词频手工整理了一份IT词汇表,共计12000个,基本囊括了常见的中英文IT词汇,欢迎各位提出交流意见. 点此 下载

  2. ckeditor 前段js配置toolbar以及取值(实用)

    <%@ page contentType="text/html;charset=UTF-8"%><%@ include file="/WEB-INF/v ...

  3. 建站笔记1:centos6.5下安装mysql

    近期买了个域名,想要玩玩自己建站点:接下来遇到的问题都会一次记录下来.以备自己以后复习查看: 首先建站方案选择: wordPress +centos6.5 +mysql; server买的:搬瓦工最低 ...

  4. 搭建Vue环境总是出错,就重新安装就好了

    总是报错,还不如重新安装.. 错误千奇百怪,解决了 这个错误又会出现另外一个. 百度了一个挺好用的e 在window下搭建Vue.Js开发环境   nodejs官网http://nodejs.cn/下 ...

  5. The promises and challenges of std::async task-based parallelism in C++11 C++11 std::async/future/promise

    转载 http://eli.thegreenplace.net/2016/the-promises-and-challenges-of-stdasync-task-based-parallelism- ...

  6. 用MyEclipse10.0远程连接Mysql数据库服务器

    说明:本文档所有的操作均在满足以下条件的情况下操作, A.远程Linux服务器已经安装好MySQL数据库 B.本地电脑可以ping通远程服务器 C.已经成功安装了Myeclipse 一.下载mysql ...

  7. Javascript 判断网页横竖屏

    本篇文章由:http://xinpure.com/javascript-to-determine-page-anyway-screen/ Html5 流行至今,自适应的网站已经多如牛毛,但是横竖屏的切 ...

  8. Ubuntu下开启mysql远程登陆权限

    在腾讯云上租了个云服务器,并且安装启动了mysql. 这时候用本地的mysql workbench去连接就会报错,提示无法成功连接. 其实这是因为没有开启账户的远程登陆权限.那么下面就开启一下: 1. ...

  9. C# 异或校验算法

    C# 的异或校验算法 直接上代码 public partial class FormCRC : Form { public FormCRC() { InitializeComponent(); } p ...

  10. 微信公共服务平台开发(.Net 的实现)4-------语音识别

    语音识别这个功能属于高级功能,必须微信实名认证后才能实现,认证费用300元/年,如果你作为开发者可以申请测试帐号,也是可以的.首先建立一个微信消息类,这个类比之前多了一个属性. class wxmes ...