终于来写博客了= =
一般的最大流
算法:dinic 博主只会这个
大概就是先bfs分层,在增广的时候只走跨层边
加当前弧优化好像快10倍左右,加的时候小心点,容易错
应该只有我会写成暴力吧
算法:dinic 博主只会这个
大概就是先bfs分层,在增广的时候只走跨层边
加当前弧优化好像快10倍左右,加的时候小心点,容易错
应该只有我会写成暴力吧
UPD:又打错了一次hhhhhhh 2017/7/15
struct edge{int t,f,n;}E[M];
void add(int x,int y,int f){
E[++tot]=(edge){y,f,ft[x]},ft[x]=tot;
E[++tot]=(edge){x,0,ft[y]},ft[y]=tot;
}
#define FOR for (int o=cu[u],v;v=E[o].t;o=E[o].n)
//写图论用的define cu为当前弧
void bfs(int u=S){
memset(d,0,sizeof(d));
memcpy(cu,ft,sizeof(cu));
for (d[q[h=t=1]=u]=1;h<=t;u=q[++h])
FOR if (E[o].f&&!d[v]) d[q[++t]=v]=d[u]+1;
}
int dfs(int u,int f){
if (u==T||!f) return f;
int g=0,t;
FOR if (cu[u]=o,d[v]==d[u]+1&&(t=dfs(v,min(f,E[o].f))))
g+=t,f-=t,E[o].f-=t,E[o^1].f+=t;
return g;
}
int main(){
int ans=0;
while (bfs(),d[T]) dfs(S,1e8);
}
一般的费用流
算法:SPFA+EK 还是只会最朴素的一种T_T
每次贪心走费用最小的增广路径
算法:SPFA+EK 还是只会最朴素的一种T_T
每次贪心走费用最小的增广路径
bool SPFA(int u){
memset(dis,0x7f,n+1<<3);
unsigned short h=0,t=0;
for (dis[q[t++]=u]=0;h!=t;){
in[u=q[h++]]=0;
FOR if (E[o].f&&dis[v]>dis[u]+E[o].c){
dis[v]=dis[u]+E[o].c,pre[v]=o;
if (!in[v]) if (in[q[t++]=v]=1,
dis[v]<dis[q[h]]) swap(q[t-1],q[h]); //SLF
}
}
return dis[T]<1<<60;
}
int dfs(int u,int f){ //递归增广
if (u==S) return cst+=dis[T]*f,f;
int t=dfs(E[pre[u]^1].t,min(f,E[pre[u]].f));
E[pre[u]].f-=t,E[pre[u]^1].f+=t;
return t;
}
int mincmf(){
while (SPFA(S)) dfs(T,1e7);
return cst;
}
最大费用可行流
有源汇就一直跑到流的费用为负为止
无源汇做法:强制费用为正的边满流,建立源汇来满足流量等式,源流向缺流的点,多流的点流向汇
最后把源汇互换,跑一边最小费用最大流,即把从源流来的流量退回去
答案就是正权边费用之和减去最小费用
有源汇就一直跑到流的费用为负为止
无源汇做法:强制费用为正的边满流,建立源汇来满足流量等式,源流向缺流的点,多流的点流向汇
最后把源汇互换,跑一边最小费用最大流,即把从源流来的流量退回去
答案就是正权边费用之和减去最小费用
void push(int x,int y,int f,int c){
if (c>0){
deg[x]+=f,deg[y]-=f,sum+=LL(f)*c;
add(x,y,f,c);
} else add(y,x,f,-c);
}
LL cal(){
for (i=1;i<n-1;i++){
if (deg[i]>0) add(S,i,deg[i],0);
if (deg[i]<0) add(i,T,-deg[i],0);
}
return sum-mincmf();
}
上下界可行流
无源汇做法:强制流满下界,流量限制变为0~mx-mn,同上建立源汇满足流量等式
对源汇做最大流,如果跑不满新加的边则说明没有可行流,否则有
有源汇做法类似, 先从汇连一条上限INF的边到源,然后用无源汇做法消掉下界,就可以知道有没有可行流
若要求最大流,则用原本的源到汇做最大流
要求最小流则从汇到源做最大流,即尽可能退流
void lim(int x,int y,int l,int r,int c=0){
cost+=1ll*c*l; //这是上下界费用流的费用
deg[x]-=l,deg[y]+=l;
if (r!=l) add(x,y,r-l,c);
}
上下界费用流
无源汇做法:类似上下界可行流,消去下界时改为跑最小费用最大流
然后。。。好像有点不对劲
算了继续留坑=w=