上下界网络流
代码均使用自这里,特此注明出处。
无源汇上下界可行流
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e4+1212;
const int N=250;
const int inf=0x3f3f3f3f;
int ed[N],st[N],s,t,cnt,head[N],n,m,tflow,d[N],l[maxn],cur[N];
struct node {
int next,to,cap,flow;
} e[maxn<<1];
void Add(int from,int to,int cap,int flow) {
e[cnt].next=head[from];
e[cnt].cap=cap;
e[cnt].flow=flow;
e[cnt].to=to;
head[from]=cnt++;
}
bool BFS(int s,int t) {//分层
memset(d,0,sizeof(d));
for(int i=0; i<=n+1; i++)//复制每个点的head
cur[i]=head[i];
queue<int>q;
q.push(s);
d[s]=1;
while(!q.empty()) {
int u=q.front();
q.pop();
for(int i=head[u]; ~i; i=e[i].next) {
int v=e[i].to;
if(!d[v]&&e[i].cap>e[i].flow) {//如果可以增流
d[v]=d[u]+1;
q.push(v);
if(v==t)return 1;
}
}
}
return 0;
}
int DFS(int u,int flow,int t) {
if(u==t)return flow;
int res=flow;//res存储当前节点的可增流值
for(int i=cur[u]; ~i&&res; i=e[i].next) {//遍历满足条件的邻边并增流
cur[u]=i;//当前弧优化
int v=e[i].to;
if(d[v]==d[u]+1&&e[i].cap>e[i].flow) {
int k=DFS(v,min(res,e[i].cap-e[i].flow),t);//获得最小的回溯流
if(!k) {
d[v]=0;
continue;
}
e[i].flow+=k;//获得最小的回溯流后增流
e[i^1].flow-=k;
res-=k;//可增流值减少,因为已经有邻边增流
}
}
return flow-res;//返回实际的总增流值
}
int Dinic(int s,int t) {
int ans=0;//存储最大流
while(BFS(s,t))for(int i=1;i<=n;i++)ans+=DFS(s,inf,t);
return ans;
}
signed main() {
//freopen("test.txt","r",stdin);
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n>>m;
memset(head,-1,sizeof(head));
for(int i=1; i<=m; i++) {
int u,v,low,up;
cin >>u>>v>>low>>up;
Add(u,v,up-low,0);
Add(v,u,0,0);
st[u]+=low;
ed[v]+=low;
tflow+=low;
l[i]=low;//记录边的,不要求输出答案可以不要
}
s=0,t=n+1;
for(int i=1; i<=n; i++) {
Add(s,i,ed[i],0);
Add(i,s,0,0);
Add(i,t,st[i],0);
Add(t,i,0,0);
}
if(Dinic(s,t)^tflow) cout <<"NO";
else {
cout <<"YES\n";
for(int i=1; i<=m; i++)
cout <<e[2*(i-1)].flow+l[i]<<endl;
}
return 0;
}
有源汇上下界最大流
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e4+1212;
const int N=250;
const int inf=0x3f3f3f3f;
int ed[N],st[N],s,t,sx,tx,cnt,head[N],n,m,tflow,d[N],cur[N];
struct node {
int next,to,cap,flow;
} e[maxn<<1];
void Add(int from,int to,int cap,int flow) {
e[cnt].next=head[from];
e[cnt].cap=cap;
e[cnt].flow=flow;
e[cnt].to=to;
head[from]=cnt++;
}
bool BFS(int s,int t) {//分层
memset(d,0,sizeof(d));
for(int i=0; i<=n+1; i++)//复制每个点的head
cur[i]=head[i];
queue<int>q;
q.push(s);
d[s]=1;
while(!q.empty()) {
int u=q.front();
q.pop();
for(int i=head[u]; ~i; i=e[i].next) {
int v=e[i].to;
if(!d[v]&&e[i].cap>e[i].flow) {//如果可以增流
d[v]=d[u]+1;
q.push(v);
if(v==t)return 1;
}
}
}
return 0;
}
int DFS(int u,int flow,int t) {
if(u==t)return flow;
int res=flow;//res存储当前节点的可增流值
for(int i=cur[u]; ~i&&res; i=e[i].next) {//遍历满足条件的邻边并增流
cur[u]=i;//当前弧优化
int v=e[i].to;
if(d[v]==d[u]+1&&e[i].cap>e[i].flow) {
int k=DFS(v,min(res,e[i].cap-e[i].flow),t);//获得最小的回溯流
if(!k) {
d[v]=0;
continue;
}
e[i].flow+=k;//获得最小的回溯流后增流
e[i^1].flow-=k;
res-=k;//可增流值减少,因为已经有邻边增流
}
}
return flow-res;//返回实际的总增流值
}
int Dinic(int s,int t) {
int ans=0;//存储最大流
while(BFS(s,t))for(int i=1; i<=n; i++)ans+=DFS(s,inf,t);
return ans;
}
signed main() {
//freopen("test.txt","r",stdin);
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n>>m>>s>>t;
memset(head,-1,sizeof(head));
for(int i=1; i<=m; i++) {
int u,v,low,up;
cin >>u>>v>>low>>up;
Add(u,v,up-low,0);
Add(v,u,0,0);
st[u]+=low;
ed[v]+=low;
tflow+=low;
//l[i]=low;
}
sx=0,tx=n+1;
for(int i=1; i<=n; i++) {
Add(sx,i,ed[i],0);
Add(i,sx,0,0);
Add(i,tx,st[i],0);
Add(tx,i,0,0);
}
Add(t,s,inf,0);
Add(s,t,0,0);
if(Dinic(sx,tx)^tflow) cout <<"please go home to sleep";
else
cout <<Dinic(s,t)<<endl;
return 0;
}
有源汇上下界最小流
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+30000;
const int N=7e4+5;
const int inf=1e10;
int ed[N],st[N],s,t,sx,tx,cnt,head[N],n,m,tflow,d[N],cur[N];
struct node {
int next,to,cap,flow;
} e[maxn<<1];
void Add(int from,int to,int cap,int flow) {
e[cnt].next=head[from];
e[cnt].cap=cap;
e[cnt].flow=flow;
e[cnt].to=to;
head[from]=cnt++;
}
bool BFS(int s,int t) {//分层
memset(d,0,sizeof(d));
for(int i=0; i<=n+1; i++)//复制每个点的head
cur[i]=head[i];
queue<int>q;
q.push(s);
d[s]=1;
while(!q.empty()) {
int u=q.front();
q.pop();
for(int i=head[u]; ~i; i=e[i].next) {
int v=e[i].to;
if(!d[v]&&e[i].cap>e[i].flow) {//如果可以增流
d[v]=d[u]+1;
q.push(v);
if(v==t)return 1;
}
}
}
return 0;
}
int DFS(int u,int flow,int t) {
if(u==t)return flow;
int res=flow;//res存储当前节点的可增流值
for(int i=cur[u]; ~i&&res; i=e[i].next) {//遍历满足条件的邻边并增流
cur[u]=i;//当前弧优化
int v=e[i].to;
if(d[v]==d[u]+1&&e[i].cap>e[i].flow) {
int k=DFS(v,min(res,e[i].cap-e[i].flow),t);//获得最小的回溯流
if(!k) {
d[v]=0;
continue;
}
e[i].flow+=k;//获得最小的回溯流后增流
e[i^1].flow-=k;
res-=k;//可增流值减少,因为已经有邻边增流
}
}
return flow-res;//返回实际的总增流值
}
int Dinic(int s,int t) {
int ans=0;//存储最大流
while(BFS(s,t))ans+=DFS(s,inf,t);
return ans;
}
signed main() {
//freopen("4.in","r",stdin);
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n>>m>>s>>t;
memset(head,-1,sizeof(head));
for(int i=1; i<=m; i++) {
int u,v,low,up;
cin >>u>>v>>low>>up;
Add(u,v,up-low,0);
Add(v,u,0,0);
st[u]+=low;
ed[v]+=low;
tflow+=low;
}
sx=0,tx=n+1;
for(int i=1; i<=n; i++) {
Add(sx,i,ed[i],0);
Add(i,sx,0,0);
Add(i,tx,st[i],0);
Add(tx,i,0,0);
}
tflow-=Dinic(sx,tx);
Add(t,s,inf,0);
Add(s,t,0,0);
tflow-=Dinic(sx,tx);
if(tflow) cout <<"please go home to sleep";
else
cout <<e[cnt-2].flow;
return 0;
}
有源汇上下界最小费用可行流
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e4+5;
const int N=1212;
const int inf=0x3f3f3f3f;
int ed[N],st[N],s,t,sx,tx,cnt,head[N],n,m,tflow,dis[N],pre[N];
bool vis[N];
struct node {
int next,to,cap,flow,pay;
} e[maxn<<1];
void Add(int from,int to,int cap,int flow,int pay) {
e[cnt].to=to;
e[cnt].cap=cap;
e[cnt].flow=flow;
e[cnt].pay=pay;
e[cnt].next=head[from];
head[from]=cnt++;
}
bool SPFA(int s,int t) {
queue<int>q;
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
vis[s]=1;
q.push(s);
while(!q.empty()) {
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u]; ~i; i=e[i].next) {
int v=e[i].to;
if(e[i].cap>e[i].flow&&dis[v]>dis[u]+e[i].pay) {
dis[v]=dis[u]+e[i].pay;
pre[v]=i;
if(vis[v])continue;
vis[v]=1;
q.push(v);
}
}
}
return pre[t]!=-1;
}
int MCMF(int s,int t) {
int mincost=0;
while(SPFA(s,t)) {
int d=inf,v=t;
while(v!=s) {
int i=pre[v];
d=min(d,e[i].cap-e[i].flow);//可增加的流量
v=e[i^1].to;//换点
}
v=t;
while(v!=s) {
int i=pre[v];
e[i].flow+=d;
e[i^1].flow-=d;//实流
v=e[i^1].to;
}
mincost+=dis[t]*d;
}
return mincost;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n;
memset(head,-1,sizeof(head));
s=0,t=n+1,sx=t+1,tx=t+2;
Add(s,1,inf,0,0),Add(1,s,0,0,0);
for(int u=1; u<=n; u++) {
cin >>m;
while(m--) {
int v,p;
cin >>v>>p;
Add(u,v,inf,0,p);
Add(v,u,0,0,-p);
st[u]++,ed[v]++;//这里的下界都是1
tflow+=p;//加上1*p
}
}
Add(t,s,inf,0,0);
Add(s,t,0,0,0);
for(int i=1; i<=n; i++) {
Add(sx,i,ed[i],0,0);
Add(i,sx,0,0,0);
Add(i,tx,st[i],0,0);
Add(tx,i,0,0,0);
Add(i,t,inf,0,0);//需要与汇点连接,不要想当然
Add(t,i,0,0,0);
}
cout <<MCMF(sx,tx)+tflow;
return 0;
}