网络流库
最大流库
使用 Dinic 实现,支持输出最小割。
#include<iostream>
#ifndef DINIC_HPP
#include<vector>
#include<queue>
#include<algorithm>
#include<limits>
namespace _dinic{
namespace __detail{
using size_t=long long;
template<size_t Node_cnt,typename Flow_type=long long>
class dinic{
struct ed_t{
bool isori;
size_t v,rid;
Flow_type flo;
};
std::vector<ed_t> *ed;
size_t _S,_T;
Flow_type _ans;
size_t *lev,*cur;
size_t _ncnt;
bool _bfs(){
std::fill(lev,lev+_ncnt+1,-1);
lev[_S]=1;
std::queue<size_t> que;
que.push(_S);
while(!que.empty()){
size_t u=que.front();
que.pop();
for(auto &e:ed[u]){
if(e.flo==0) continue;
if(lev[e.v]==-1){
lev[e.v]=lev[u]+1;
que.push(e.v);
}
}
}
return lev[_T]!=-1;
}
Flow_type _dfs(size_t it,Flow_type tflo){
if(it==_T) return tflo;
Flow_type rest=tflo;
for(size_t &i=cur[it];i<(size_t)ed[it].size();++i){
auto &e=ed[it][i];
if(e.flo==0||lev[e.v]!=lev[it]+1) continue;
Flow_type rec=_dfs(e.v,std::min(rest,e.flo));
if(rec==0){
lev[e.v]=-1;
}else{
e.flo-=rec;
rest-=rec;
ed[e.v][e.rid].flo+=rec;
if(rest==0) break;
}
}
return tflo-rest;
}
public:
dinic(int S,int T):
ed(new std::vector<ed_t>[Node_cnt+1]),
_S(S),_T(T),_ans(0),
lev(new size_t[Node_cnt+1]),
cur(new size_t[Node_cnt+1]),
_ncnt(0){}
dinic(const dinic &o)=delete;
dinic &operator=(const dinic &o)=delete;
dinic(dinic &&o)=delete;
~dinic(){
delete[] ed;
delete[] lev;
delete[] cur;
}
void add_edge(size_t u,size_t v,Flow_type flo){
ed_t fo{true,v,(size_t)ed[v].size(),flo},ba{false,u,(size_t)ed[u].size(),0};
ed[u].push_back(fo);
ed[v].push_back(ba);
if(_ncnt<u) _ncnt=u;
if(_ncnt<v) _ncnt=v;
return ;
}
Flow_type max_flow(){
while(_bfs()){
std::fill(cur,cur+_ncnt+1,0);
_ans+=_dfs(_S,std::numeric_limits<Flow_type>::max());
}
return _ans;
}
std::vector<std::pair<size_t,size_t> > get_min_cut(){
std::vector<std::pair<size_t,size_t> > ret;
for(size_t i=1;i<=_ncnt;++i){
for(auto &e:ed[i]){
if(e.isori&&e.flo==0){
ret.push_back(std::make_pair(i,e.v));
}
}
}
return ret;
}
};
} //namespace __detail
using __detail::dinic;
}//namespace _dinic
#endif // DINIC_HPP
#include<iostream>
using namespace std;
constexpr int MAXN=200,MAXM=500;
int N=0,M=0,S=0,T=0;
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin>>N>>M>>S>>T;
_dinic::dinic<MAXN> G(S,T);
for(int i=1;i<=M;i++){
int u,v,flo;
cin>>u>>v>>flo;
G.add_edge(u,v,flo);
}
cout<<G.max_flow()<<endl;
return 0;
}
费用流库
使用 SPFA + EK 实现。
#include<iostream>
#include<vector>
#include<limits>
#include<deque>
template<int NSIZ,typename Flow_t,typename Cost_t,typename Comp=std::less<Cost_t> >
class min_cost_max_flow_t{
static Cost_t min(const Cost_t &a,const Cost_t &b){return Comp()(b,a)?b:a;}
static bool tomin(Cost_t &a,const Cost_t &b){if(Comp()(b,a)){a=b; return 1;} return 0;}
struct ed_t{
int v,r; Flow_t f; Cost_t c;
bool operator>(const ed_t &o)const{
return Comp()(o.c,c);
}
};
int ncnt;
std::vector<std::vector<ed_t> > ed;
std::vector<char> vis;
std::vector<Cost_t> dis;
std::vector<Flow_t> Flow;
std::vector<int> rev;
std::deque<int> dque;
std::vector<char> in;
void upd(){
if(dque.size()>=2){
if(Comp()(dis[dque.back()],dis[dque.front()]))
std::swap(dque.front(),dque.back());
}
return ;
}
void spfa(int S){
std::fill(vis.begin(),vis.begin()+ncnt+1,0);
std::fill(Flow.begin(),Flow.begin()+ncnt+1,0);
std::fill(rev.begin(),rev.begin()+ncnt+1,-1);
dis[S]=0; Flow[S]=std::numeric_limits<Flow_t>::max();
vis[S]=1; dque.push_back(S); in[S]=1;
while(!dque.empty()){
int it=dque.front(); dque.pop_front(); in[it]=0;
upd();
for(auto e:ed[it])if(e.f>0){
if((!vis[e.v])||Comp()(dis[it]+e.c,dis[e.v])){
dis[e.v]=dis[it]+e.c;
vis[e.v]=1;
Flow[e.v]=std::min(Flow[it],e.f);
rev[e.v]=e.r;
if(!in[e.v]){
dque.push_back(e.v); in[e.v]=1;
upd();
}
}
}
}
return ;
}
public:
min_cost_max_flow_t():ncnt(0),ed(NSIZ+1),vis(NSIZ+1),
dis(NSIZ+1),Flow(NSIZ+1),rev(NSIZ+1),in(NSIZ+1){}
void connect(int u,int v,Flow_t f,Cost_t c){
if(ncnt<u) ncnt=u;
if(ncnt<v) ncnt=v;
int usiz=ed[u].size(),vsiz=ed[v].size();
ed[u].push_back({v,vsiz,f,c});
ed[v].push_back({u,usiz,0,-c});
return ;
}
std::pair<Flow_t,Cost_t> maxflow(int S,int T){
Flow_t flow=0; Cost_t cost=0;
while(1){
spfa(S);
if(rev[T]==-1) break;
Flow_t f=Flow[T];
flow+=f;
for(int it=T;rev[it]!=-1;){
auto &re=ed[it][rev[it]];
auto &e=ed[re.v][re.r];
cost+=e.c*f;
e.f-=f;
re.f+=f;
it=re.v;
}
}
return {flow,cost};
}
};
using ll=long long;
constexpr int MAXN=5e3,MAXM=5e4;
int main(){
min_cost_max_flow_t<MAXN,ll,ll> G;
using std::cin; using std::cout;
int n,m,s,t; cin>>n>>m>>s>>t;
for(int i=1;i<=m;i++){
int u,v,w,c; cin>>u>>v>>w>>c;
G.connect(u,v,w,c);
}
auto pi=G.maxflow(s,t);
cout<<pi.first<<' '<<pi.second<<'\n';
return 0;
}
费用流库(二)
使用网络单纯形算法实现,期望复杂度 \(O(nm)\)(\(n,m\) 分别为点数和边数),擅长稠密图。
#include<bits/stdc++.h>
/*
* Watch out!
* The sum of cost times the sum of flow must less than the limit of type!
*/
template<int Node_cnt,int Edge_cnt,typename cost_t,typename flow_t>
class min_cost_max_flow_t{
template<typename Tp>
static bool tomin(Tp &x,const Tp &y){if(y<x){x=y; return 1;} return 0;}
static constexpr int NSI=Node_cnt,ESI=(Edge_cnt+1)*2;
struct ed_t{int nxt,to; flow_t f; cost_t c;};
int n,m,S,T;
std::vector<char> vis;
std::vector<int> hd,Fa,Fe,dep,buf;
std::vector<cost_t> dis;
std::vector<ed_t> E;
void build(int it,int fa,int fe){
vis[it]=1;
Fa[it]=fa; Fe[it]=fe;
for(int j=hd[it];j!=0;j=E[j].nxt)if(!vis[E[j].to]){
build(E[j].to,it,j^1);
}
return ;
}
void upd(int it){
if(it==0||vis[it]) return ;
vis[it]=1;
upd(Fa[it]);
dep[it]=dep[Fa[it]]+1;
dis[it]=dis[Fa[it]]+E[Fe[it]].c;
return ;
}
int getlca(int x,int y){
while(x!=y) (dep[y]>=dep[x])?y=Fa[y]:x=Fa[x];
return x;
}
void pushflow(int j){
int l=NSI,r=NSI;
buf[l]=j;
int u=E[j^1].to,v=E[j].to;
int lca=getlca(u,v);
for(int i=u;i!=lca;i=Fa[i]) buf[--l]=Fe[i]^1;
for(int i=v;i!=lca;i=Fa[i]) buf[++r]=Fe[i];
int del=NSI; cost_t f=E[j].f;
for(int i=l;i<=r;i++) if(tomin(f,E[buf[i]].f)) del=i;
for(int i=l;i<=r;i++){int s=buf[i]; E[s].f-=f; E[s^1].f+=f;}
if(del==NSI) return ;
if(del<NSI){
for(int i=del+1;i<=NSI;i++){
int s=buf[i];
Fa[E[s^1].to]=E[s].to;
Fe[E[s^1].to]=s;
}
}else{
for(int i=NSI;i<=del-1;i++){
int s=buf[i];
Fa[E[s].to]=E[s^1].to;
Fe[E[s].to]=s^1;
}
}
std::fill(vis.begin()+1,vis.begin()+n+1,0);
return ;
}
public:
min_cost_max_flow_t():n(0),m(1),S(0),T(0),
vis(NSI+5,0),hd(NSI+5,0),Fa(NSI+5,0),Fe(NSI+5,0),dep(NSI+5,0),buf(NSI*2+5,0),
dis(NSI+5,0),E(ESI+5){}
void connect(int u,int v,flow_t f,cost_t c){
E[++m]={hd[u],v,f,c}; hd[u]=m;
E[++m]={hd[v],u,0,-c}; hd[v]=m;
return ;
}
std::pair<flow_t,cost_t> solve(int _n,int _s,int _t){
n=_n; S=_s, T=_t;
flow_t sflow=0; cost_t scost=0;
for(int j=2;j<=m;j++){
auto &e=E[j];
sflow+=e.f; if(e.c>0) scost+=e.c;
}
connect(S,T,sflow,scost+1);
std::swap(E[m-1].f,E[m].f);
flow_t flow=0; cost_t cost=0;
build(S,0,0); std::fill(vis.begin()+1,vis.begin()+n+1,0);
while(1){
bool ok=0;
for(int j=2;j<=m;j++){
auto &e=E[j];
if(e.f>0){
int u=E[j^1].to,v=e.to;
upd(u); upd(v);
if(e.c-dis[u]+dis[v]<0){
pushflow(j);
ok=1;
}
}
}
if(!ok) break;
}
for(int j=3;j<m;j+=2){
auto &e=E[j];
if(e.to==S) flow+=e.f;
if(E[j^1].to==S) flow-=e.f;
cost+=-e.c*e.f;
}
return {flow,cost};
}
};
using std::cerr; using std::setw; using std::endl; using std::cin; using std::cout;
template<typename Tp>
bool tomax(Tp &x,const Tp &y){if(x<y){x=y; return 1;} return 0;}
template<typename Tp>
bool tomin(Tp &x,const Tp &y){if(y<x){x=y; return 1;} return 0;}
using ll=long long; using ui=unsigned; using lf=double; using ull=unsigned long long;
constexpr int MAXN=200,MAXM=1e4;
int main(){
std::ios::sync_with_stdio(0); std::cin.tie(0); std::cout.tie(0);
int N,M,S,T;
min_cost_max_flow_t<MAXN,MAXM,int,int> G;
cin>>N>>M>>S>>T;
for(int m=1;m<=M;m++){
int u,v,f,c; cin>>u>>v>>f>>c;
G.connect(u,v,f,c);
}
auto pi=G.solve(N,S,T);
cout<<pi.first<<' '<<pi.second<<'\n';
return 0;
}

浙公网安备 33010602011771号