区域赛在急,看看了上下界网络流,引水思源,这里给个出处 [上下界网络流]https://www.cnblogs.com/liu-runda/p/6262832.html
这里只简单记录建图方法
无源汇可行流
建图
- u->v upper-lower 在源边上建容量上限为 upper-lower的边
- 计算每条边的 totflow[u]=∑in[u]−∑out[u]
- 对于每个点 totflow[u]>0,s−>u,totflow[u] ,反之建 i−>t,−totflow[i]
- 跑 s−t 最大流,如果最大流等于总需要流入的流量( ∑totflow[u]>0totflow[u] ) 说明可行.
- 每条边的实际流量为low[i] + s-t 最大流跑完后边的流量
例题 zoj 2314
#include <bits/stdc++.h>
using namespace std;
#define ms(x,v) (memset((x),(v),sizeof(x)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define INF 0x3f3f3f3f
typedef long long LL;
typedef pair<int,int > Pair;
const int MAX_V = 200+10;
const int MAX_E = 1e5+10;
int n,m;
namespace dinic{
int ne =0,s,t;
struct Edge{
int from ,to,cap;
Edge(int u=0,int v=0,int c =0):from(u),to(v),cap(c){};
} E[MAX_E<<2];
std::vector<int> G[MAX_V];
int level[MAX_V],cur[MAX_V];
inline void add_edge(int u,int v,int cap) {
E[ne] = Edge(u,v,cap);G[u].pb(ne++);
E[ne] = Edge(v,u,0); G[v].pb(ne++);
}
void bfs(int s) {
ms(level,-1);
queue<int > Q;Q.push(s);
level[s] =0;
while (!Q.empty()) {
int u = Q.front();Q.pop();
for(int i=0 ; i< G[u].size() ; ++i){
Edge &e = E[G[u][i]];
if(e.cap >0 && level[e.to] <0){level[e.to] = level[u]+1 ; Q.push(e.to);}
}
}
}
int dfs(int v,int t,int f){
if(v ==t || f==0)return f;
for(int &i = cur[v] ; i<G[v].size() ; ++i){
Edge & e = E[G[v][i]];Edge & rev = E[G[v][i]^1];
if(e.cap>0 && level[v] <level[e.to]){
int a = dfs(e.to,t,min(f,e.cap));
if(a > 0){e.cap -=a ; rev.cap += a;return a;}
}
}
return 0;
}
int max_flow(int s,int t){
int flow = 0;
for(;;){
bfs(s);
if(level[t] < 0 )break;
ms(cur,0);
int f;
while ((f = dfs(s,t,INF)) > 0)flow += f;
}
return flow;
}
}
using namespace dinic;
int totflow[MAX_V];
int low[MAX_E];
int main(int argc, char const *argv[]) {
int T;
scanf("%d",&T);
while (T--) {
ne =0;
ms(totflow,0);
scanf("%d%d",&n,&m);
s = 0;t = n+1;
for(int i=0 ; i<m ; ++i){
int u,v,c;
scanf("%d%d%d%d",&u,&v,&low[i],&c);
add_edge(u,v,c-low[i]);totflow[u] -=low[i];totflow[v] += low[i];
}
int sum=0;
for(int i=1 ; i<=n ; ++i)
if(totflow[i]>0)add_edge(s,i,totflow[i]),sum += totflow[i];
else add_edge(i,t,-totflow[i]);
if(max_flow(s,t) == sum){
printf("YES\n");
for(int i=1 ; i<2*m ; i+=2)printf("%d\n",low[(i>>1)]+ E[i].cap);
}else printf("NO\n");
for(int i=s ; i<=t ; ++i)G[i].clear();
}
return 0;
}
有源汇上下界可行流.
只需连一条 t−s 容量无限的边就是 上面的模型了.
建图
- u->v upper-lower 在源边上建容量上限为 upper-lower的边
- 计算每条边的 totflow[u]=∑in[u]−∑out[u]
- 建新的原点,汇点 ss,tt
- 对于每个点 totflow[u]>0,ss−>u,totflow[u] ,反之建 i−>tt,−totflow[i]
- 跑 ss−tt 最大流,判断是否可行,
这个是下面两个的基础
有源汇上下界最大流
建图
- 同上.先求可行流设为 f=E[t−s].flow (残量网络中的容量)
- 将新边( t−s,inf )中 s−t 的容量设为0, 这就等价于上面那片blog 说的重新重 s−t 增广. 得出最大流 f′ , f+f′ 为实际最大流,
不过对于我的模板来说,其实不必有第一步,因为我们只需在 ss−tt 的残量网络上直接增广就行因此可以 直接求 s−t 的最大流
loj 116
#include <bits/stdc++.h>
using namespace std;
#define ms(x,v) (memset((x),(v),sizeof(x)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define INF 0x3f3f3f3f
typedef long long LL;
typedef pair<int,int > Pair;
const int MAX_V = 300;
const int MAX_E = 1e5+10;
int n,m;
namespace dinic{
int ne =0,s,t;
struct Edge{
int from ,to,cap;
Edge(int u=0,int v=0,int c =0):from(u),to(v),cap(c){};
} E[MAX_E<<2];
std::vector<int> G[MAX_V];
int level[MAX_V],cur[MAX_V];
inline void add_edge(int u,int v,int cap) {
E[ne] = Edge(u,v,cap);G[u].pb(ne++);
E[ne] = Edge(v,u,0); G[v].pb(ne++);
}
void bfs(int s) {
ms(level,-1);
queue<int > Q;Q.push(s);
level[s] =0;
while (!Q.empty()) {
int u = Q.front();Q.pop();
for(int i=0 ; i< G[u].size() ; ++i){
Edge &e = E[G[u][i]];
if(e.cap >0 && level[e.to] <0){level[e.to] = level[u]+1 ; Q.push(e.to);}
}
}
}
int dfs(int v,int t,int f){
if(v ==t || f==0)return f;
for(int &i = cur[v] ; i<G[v].size() ; ++i){
Edge & e = E[G[v][i]];Edge & rev = E[G[v][i]^1];
if(e.cap>0 && level[v] <level[e.to]){
int a = dfs(e.to,t,min(f,e.cap));
if(a > 0){e.cap -=a ; rev.cap += a;return a;}
}
}
return 0;
}
int max_flow(int s,int t){
int flow = 0;
for(;;){
bfs(s);
if(level[t] < 0 )break;
ms(cur,0);
int f;
while ((f = dfs(s,t,INF)) > 0)flow += f;
}
return flow;
}
}
using namespace dinic;
int totflow[MAX_V];
int low[MAX_E];
int main(int argc, char const *argv[]) {
scanf("%d%d%d%d",&n,&m,&s,&t );
for(int i=0 ; i<m ; ++i){
int u,v,l,up;
scanf("%d%d%d%d",&u,&v,&l,&up );
add_edge(u,v,up-l);
totflow[u]-=l;totflow[v] += l;low[i] = l;
}
int sum =0;
int ss = 0,tt = n+1;
for(int i=1 ; i<=n ; ++i)
if(totflow[i]>0)add_edge(ss,i,totflow[i]),sum+=totflow[i];
else add_edge(i,tt,-totflow[i]);
add_edge(t,s,INF);
if(max_flow(ss,tt) == sum){
int f = E[ne-1].cap;
E[ne-1].cap =0;
printf("%d\n",f+ max_flow(s,t));
//or printf("%d\n",max_flow(s,t));
}else printf("please go home to sleep\n");
return 0;
}
有源汇上下界最小流
建图
- 同上,先求可行流,求出流量 f=E[t−s].flow
- 将 t−s 的容量设为0 重跑 f′=max_flow(t,s) 表示回退流量,最小流为 f−f′
loj 117
#include <bits/stdc++.h>
using namespace std;
#define ms(x,v) (memset((x),(v),sizeof(x)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define INF 0x3f3f3f3f
typedef long long LL;
typedef pair<int,int > Pair;
const int MAX_V = 50000+100;
const int MAX_E = 125000+10;
int n,m;
typedef LL cap_type;
namespace dinic{
int ne =0,s,t;
struct Edge{
int from ,to;
cap_type cap;
Edge(int u=0,int v=0,cap_type c =0):from(u),to(v),cap(c){};
} E[MAX_E<<2];
std::vector<int> G[MAX_V];
int level[MAX_V],cur[MAX_V];
inline void add_edge(int u,int v,cap_type cap) {
E[ne] = Edge(u,v,cap);G[u].pb(ne++);
E[ne] = Edge(v,u,0); G[v].pb(ne++);
}
void bfs(int s) {
ms(level,-1);
queue<int > Q;Q.push(s);
level[s] =0;
while (!Q.empty()) {
int u = Q.front();Q.pop();
for(int i=0 ; i< G[u].size() ; ++i){
Edge &e = E[G[u][i]];
if(e.cap >0 && level[e.to] <0){level[e.to] = level[u]+1 ; Q.push(e.to);}
}
}
}
cap_type dfs(int v,int t,cap_type f){
if(v ==t || f==0)return f;
for(int &i = cur[v] ; i<G[v].size() ; ++i){
Edge & e = E[G[v][i]];Edge & rev = E[G[v][i]^1];
if(e.cap>0 && level[v] <level[e.to]){
int a = dfs(e.to,t,min(f,e.cap));
if(a > 0){e.cap -=a ; rev.cap += a;return a;}
}
}
return 0;
}
cap_type max_flow(int s,int t){
cap_type flow = 0;
for(;;){
bfs(s);
if(level[t] < 0 )break;
ms(cur,0);
cap_type f;
while ((f = dfs(s,t,INF)) > 0)flow += f;
}
return flow;
}
}
using namespace dinic;
int totflow[MAX_V];
int low[MAX_E];
int main(int argc, char const *argv[]) {
scanf("%d%d%d%d",&n,&m,&s,&t );
for(int i=0 ; i<m ; ++i){
int u,v,l,up;
scanf("%d%d%d%d",&u,&v,&l,&up );
add_edge(u,v,up-l);
totflow[u]-=l;totflow[v] += l;low[i] = l;
}
int sum =0;
int ss = 0,tt = n+1;
for(int i=1 ; i<=n ; ++i)
if(totflow[i]>0)add_edge(ss,i,totflow[i]),sum+=totflow[i];
else add_edge(i,tt,-totflow[i]);
add_edge(t,s,0x7ffffffffff);
if(max_flow(ss,tt) == sum){
//std::cout << E[ne].cap << " " << E[ne-2].cap << '\n';
cap_type f = E[ne-1].cap;
E[ne-1].cap = 0;
printf("%lld\n",f - max_flow(t,s));
}else printf("please go home to sleep\n");
return 0;
}