Flow construction SGU - 176 有源汇有上下界最小流 二分法和回流法
/** 题目: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 有源汇有上下界最小流 二分法和回流法的更多相关文章
- loj #117. 有源汇有上下界最小流
题目链接 有源汇有上下界最小流,->上下界网络流 注意细节,边数组也要算上后加到SS,TT边. #include<cstdio> #include<algorithm> ...
- LOJ.117.[模板]有源汇有上下界最小流(Dinic)
题目链接 有源汇有上下界最小流 Sol1. 首先和无源汇网络流一样建图,求SS->TT最大流: 然后连边(T->S,[0,INF]),再求一遍SS->TT最大流,答案为新添加边的流量 ...
- sgu 176 Flow construction(有源汇的上下界最小流)
[题目链接] http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=11025 [模型] 有源汇点的上下界最小流.即既满足上下界又满足 ...
- sgu176 Flow Construction【有源汇有上下界最小流】
同样是模板题. 首先将有源汇转换为无源汇,假设原来的源汇为st,我们加入的源汇为ST,那么我们应该从t到s连一条流量为+∞的边,使原来的st满足收支平衡,退化为普通节点. 分离必要边和其他边,从S到T ...
- sgu 176 有源汇有上下界的最小流模板题
/*参考博文:http://hi.baidu.com/dragon_eric123/item/82e259200ece744046996282 有上下界的有源最小流 */ #include<st ...
- 【 POJ - 3801】Crazy Circuits(有源汇、上下界最小流)
Description You’ve just built a circuit board for your new robot, and now you need to power it. Your ...
- bzoj 2502 清理雪道(有源汇的上下界最小流)
[题意] 有一个DAG,要求每条边必须经过一次,求最少经过次数. [思路] 有上下界的最小流. 边的下界为1,上界为无穷.构造可行流模型,先不加ts边跑一遍最大流,然后加上t->s的inf边跑 ...
- LOJ117 有源汇有上下界最小流(上下界网络流)
跑出可行流后从原来的汇点向原来的源点跑最大流,原图最小流=inf-maxflow.显然超源超汇的相关边对其也没有影响.原图最小流=可行流-原图新增流量,因为t向s流量增加相当于s向t流量减少.但为什么 ...
- Crazy Circuits HDU - 3157(有源汇有上下界最小流)
给出每条边的下界 求最小流 板题 提供两个板子代码 虽然这个题 第一个比较快 但在loj上https://loj.ac/problem/117 的板题 第一个1700+ms 第二个才600+ms ...
随机推荐
- windows下mysql中文乱码, 配置解决方法
内容源自:windows下mysql中文乱码, 配置解决方法 解决方法:打开mysql安装目录,打开my.ini文件(如果只有my-default.ini文件,先将其改名为my.ini!!!) 修改内 ...
- Python绘制直方图 Pygal模拟掷骰子
#coding=utf-8 from random import randint class Die(): """骰子类""" def __ ...
- cocos2d-x 3.1.1 学习笔记[15] Shader 著色器
首先须要两个文件 gray.fsh varying vec4 v_fragmentColor; varying vec2 v_texCoord; void main() { vec4 v_orColo ...
- [Unity3D]场景间切换与数据传递(以及物体删除技巧)
http://blog.163.com/kingmax_res/blog/static/77282442201031712216508/ 先介绍一些基本函数(具体用法自己查文档):---------- ...
- 关于HTML、js加密、混淆、源码保护、代码安全,防止解压直接看源码
一直有人问HTML加密混淆怎么做,其实这在业内是早已很多人研究过的课题.假日期间整理一篇文章分享给大家. 我们先理下需求,加密的目的是什么?加密到什么级别?为此我们可以牺牲什么?我们知道这个世界不存在 ...
- python求pi的方法
来自 #_*_ coding=utf-8 *_* ## {{{ http://code.activestate.com/recipes/578130/ (r5) def pi(places=10): ...
- CPU利用率与Load Average的区别?
CPU利用率,是对一个时间段内CPU使用状况的统计,通过这个指标可以看出在某一个时间段内CPU被占用的情况,如果CPU被占用时间很高,那么就需要考虑CPU是否已经处于超负荷运作,长期超负荷运作对于机器 ...
- Oracle中sign/decode/nvl/round/trunc/(+)/instr/substr/replace解释
1. sign函数 sign函数语法: sign(n); sign函数说明: 取数字n的符号,大于0返回1,小于0返回-1,等于0返回0(n可以是表达式,(n-200)) 例子: a=10; b=50 ...
- oracle 使用REGEXP_SUBSTR正则表达式拆分字符串
SELECT REGEXP_SUBSTR ('first field, second field , third field', '[^,]+', 1,rownum) FROM DUAL CONNEC ...
- iOS 键盘自适应(IQKeyboardManager)使用小结
IQKeyboardManager Github地址 经常在开发一个应用程序,我们遇到了一个问题,iPhone的键盘上滑覆盖的UITextField / UITextView.IQKeyboardMa ...