网络流板子
dinic是loj上偷学长的(
注意几点:
id初值赋1才能让正向弧反向弧对应起来
很多题要拆点,一定保证空间
dfs里当前弧优化不能放在for循环里
Talk is cheap. Show you the code.
#include<cstdio>
#include<iostream>
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(int x=0,char ch=getchar()){
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x;
}
const int N=1e2+7,M=1e4+7;
const ll inf=1e18;
int n,m,S,T;
ll ans,c[M];
int head[N],to[M],nx[M],id=1;
inline void add(int a,int b,int cc){
nx[++id]=head[a]; head[a]=id; to[id]=b; c[id]=cc;
}
inline void Add(int a,int b,int c){
add(a,b,c); add(b,a,0);
}
int q[N],hd,tl;
int dis[N],Hd[N];
inline bool bfs(){
memset(dis,0x3f,sizeof(dis));
memcpy(head,Hd,sizeof(head));
q[hd=tl=1]=S; dis[S]=0;
while(hd<=tl){
int x=q[hd++];
for(int i=head[x];i;i=nx[i]) if(c[i]){
int t=to[i];
if(dis[t]>dis[x]+1){
dis[t]=dis[x]+1;
q[++tl]=t;
}
}
if(x==T) return 1;
}
return 0;
}
ll dfs(int x,ll in){
if(x==T) return in;
ll rest=in,go;
for(int i=head[x];i;head[x]=i=nx[i]) if(c[i]){
int t=to[i];
if(dis[t]==dis[x]+1){
go=dfs(t,min(rest,c[i]));
if(go) c[i]-=go,c[i^1]+=go,rest-=go;
else dis[t]=0;
}
if(!rest) break;
}
return in-rest;
}
int main(){
n=read(); m=read();
S=read(); T=read();
while(m--){
int u=read(),v=read();
Add(u,v,read());
}
memcpy(Hd,head,sizeof(Hd));
while(bfs()) ans+=dfs(S,inf);
printf("%lld\n",ans);
return 0;
}
用自己码风写了一遍(其实差不多
#include<bits/stdc++.h>
using namespace std;
namespace IO{
typedef long long LL;
typedef double DB;
int read(){
int x=0,f=0; char ch=getchar();
while(ch<'0'||ch>'9'){ f|=(ch=='-'); ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return f?-x:x;
} char output[50];
void write(LL x,char sp){
int len=0;
if(x<0) x=-x, putchar('-');
do{ output[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(output[i]); putchar(sp);
}
void ckmin(int &x,int y){ x=x<y?x:y; }
void ckmax(int &x,int y){ x=x>y?x:y; }
} using namespace IO;
const int NN=210,MM=100010;
int n,m;
LL ans;
namespace Network_Flows{
int s,t,ql,qr,q[NN],idx=1;
int to[MM],nex[MM],hd[NN],dis[NN],head[NN];
LL c[MM];
void add(int a,int b,int d){ to[++idx]=b; nex[idx]=head[a]; head[a]=idx; c[idx]=d; }
void link(int a,int b,int c){ add(a,b,c); add(b,a,0); }
bool bfs(){
memset(dis,0x3f,sizeof(dis));
memcpy(head,hd,sizeof(hd));
q[ql=qr=1]=s; dis[s]=0;
while(ql<=qr){
int u=q[ql++];
for(int v,i=head[u];i;i=nex[i]) if(c[i])
if(dis[v=to[i]]>dis[u]+1){
dis[v]=dis[u]+1;
q[++qr]=v;
}
if(u==t) return 1;
}
return 0;
}
LL dfs(int u,LL in){
if(u==t) return in;
LL rest=in,go;
for(int v,i=head[u];i;head[u]=i=nex[i]) if(c[i]){
if(dis[v=to[i]]==dis[u]+1){
go=dfs(v,min(c[i],rest));
if(go) c[i]-=go, c[i^1]+=go, rest-=go;
else dis[v]=0;
}
if(!rest) break;
}
return in-rest;
}
void dinic(){
memcpy(hd,head,sizeof(head));
while(bfs()) ans+=dfs(s,LLONG_MAX);
}
} using namespace Network_Flows;
signed main(){
n=read(); m=read(); s=read(); t=read();
for(int u,v,i=1;i<=m;i++)
u=read(), v=read(), link(u,v,read());
dinic();
write(ans,'\n');
return 0;
}
EK最小费用最大流
#include<bits/stdc++.h>
using namespace std;
namespace IO{
typedef long long LL;
typedef double DB;
int read(){
int x=0,f=0; char ch=getchar();
while(ch<'0'||ch>'9'){ f|=(ch=='-'); ch=getchar(); }
while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
return f?-x:x;
} char output[50];
void write(LL x,char sp){
int len=0;
if(x<0) x=-x, putchar('-');
do{ output[len++]=x%10+'0'; x/=10; }while(x);
for(int i=len-1;~i;i--) putchar(output[i]); putchar(sp);
}
void ckmin(int &x,int y){ x=x<y?x:y; }
void ckmax(int &x,int y){ x=x>y?x:y; }
} using namespace IO;
const int NN=50010,MM=500010;
int n,m;
namespace Network_Flows{
int S,T,ql,qr,flow,cost,q[NN],idx=1;
int c[MM],w[MM],to[MM],nex[MM],dis[NN],inc[NN],pre[NN],head[NN];
bool vis[NN];
void add(int a,int b,int x,int y){
to[++idx]=b; nex[idx]=head[a]; head[a]=idx; c[idx]=x; w[idx]=y;
to[++idx]=a; nex[idx]=head[b]; head[b]=idx; c[idx]=0; w[idx]=-y;
}
bool spfa(){
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[S]=0; inc[S]=INT_MAX;
vis[q[ql=qr=1]=S]=1;
while(ql<=qr){
int u=q[ql++]; vis[u]=0;
for(int v,i=head[u];i;i=nex[i]) if(c[i])
if(dis[v=to[i]]>dis[u]+w[i]){
dis[v]=dis[u]+w[i];
inc[v]=min(inc[u],c[i]);
pre[v]=i;
if(!vis[v]) vis[q[++qr]=v]=1;
}
}
return dis[T]<1e9;
}
void MCMF(){
while(spfa()){
flow+=inc[T]; cost+=inc[T]*dis[T];
int u=T,i;
while(u!=S){
i=pre[u];
c[i]-=inc[T];
c[i^1]+=inc[T];
u=to[i^1];
}
}
}
} using namespace Network_Flows;
signed main(){
n=read(); m=read(); S=read(); T=read();
for(int a,b,x,y,i=1;i<=m;i++)
a=read(),b=read(),x=read(),y=read(),add(a,b,x,y);
MCMF();
write(flow,' '); write(cost,'\n');
return 0;
}
带上下界的就不放了--可以看达哥的博
先保证下界,然后连出超级源汇(如果是有源汇还要汇点向源点连边),之后该跑啥跑啥就好。
最小可行流先不连汇源跑一遍,再连上跑一遍,看汇源之间边的流量即可。
for(int i=1;i<=t;i++)
if(dis[i]>0) add(S,i,dis[i]);
else if(dis[i]<0) add(i,T,-dis[i]);
dinic();
link(t,s,0,INT_MAX);
dinic();
write(c[idx],'\n');