网络流
负权边的处理
最小费用最大流
考虑将 dinic 的bfs部分换成 SPFA,在没有负环的前提下求费用流。
但这玩意劣化成了EK阿。
最大权闭合子图
P3749 [六省联考2017]寿司餐厅 网络流:最小割,最大权闭合子图。 注意强选的条件和 正权sum-flow的转化即可。
强选打包:连inf边。先选正权和sum,再正权连S,负权连T,流量都是
其实最小割模型严格强于这个。
CF103E Buying Sets 需要较强的理解。
上下界网络流
指给出每条边的上下界。流量要在这个范围内。
无源汇上下界可行流:询问是否存在一种标定每条边流量的方式,使得每条边流量满足上下界同时每一个点流量平衡。
先连下界,这是必须的。连新边,这条边的下界是0,上界是上下界的差。这意味着我们之后能够支配的流量。考虑最终平衡:按照当前的构造一定有某些点要么需要流量要么需要流出,我们要达到的目的是将所有要流出的点作为起点,需要流量的点作为汇点,按当前网络能够流平。怎么解决呢?考虑给所有起点连一个源点,终点连一个总汇点。在新的网络上跑最大流,最后看最大流是否等于要流出的流量和。
有源汇上下界可行流:只有源汇不需要流量平衡。
考虑将
有源汇上下界最大流:在可行流的基础上求最大流。
先跑可行流,再在删去所有附加边的残量网络上跑
考虑正确性:删掉了什么附加边?在求可行流时的
有源汇上下界最小流:这个的正确性看上面括号内容。
在残量网络中跑
最大和最小唯一的区别
Can+maxflow(s,t)
Can-maxflow(t,s)
有源汇上下界最小流板子
P4843 清理雪道
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1; char s;
while((s=getchar())<'0'||s>'9') if(s=='-') f=-1;
while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+(s^'0'),s=getchar();
return x*f;
}
#define rg register int
const int inf=2100000000;
const int N=105;
int n,m,s,t,S,T,tot=1,cnt,inf_num,head[N];
int sum[N];//下界时每条边的流出流量
struct node{
int to,nxt,w;
}e[N<<7];
inline void add(int u,int v,int w){
e[++tot].to=v,e[tot].nxt=head[u],head[u]=tot,e[tot].w=w;
e[++tot].to=u,e[tot].nxt=head[v],head[v]=tot,e[tot].w=0;
}
int Can,lim;
int dis[N],now[N];
bool bfs(int S,int T){
for(int i=1;i<=n+4;++i) dis[i]=inf;
queue<int> q;
q.push(S);
dis[S]=0,now[S]=head[S];
while(!q.empty()){
int x=q.front();
q.pop();
for(rg i=head[x];i;i=e[i].nxt){
int v=e[i].to;
if(e[i].w>0&&dis[v]==inf){
dis[v]=dis[x]+1;
now[v]=head[v];
q.push(v);
if(v==T) return 1;
}
}
}
return 0;
}
int dfs(int u,int sum,int T){
if(u==T) return sum;
int k,res=0;
for(rg i=now[u];i;i=e[i].nxt){
int v=e[i].to;
now[u]=i;
if(e[i].w>0&&(dis[v]==dis[u]+1)){
k=dfs(v,min(sum,e[i].w),T);
if(k==0) dis[v]=inf;
e[i].w-=k,e[i^1].w+=k;
res+=k,sum-=k;
}
}
return res;
}
int maxflow(int S,int T){//跑S->T的最大流
int ans=0;
while(bfs(S,T)){
ans+=dfs(S,inf,T);
}
return ans;
}
int main(){
cin>>n;
s=n+1,t=n+2;
for(int i=1;i<=n;++i){
m=read();
for(int j=1;j<=m;++j){
int v=read();
add(i,v,inf-1),sum[v]+=1,sum[i]-=1;
}
}
n+=2;
for(int i=1;i<=n-2;++i){
add(s,i,inf),add(i,t,inf);
}
S=(T=n+1)+1;
for(int i=1;i<=n-2;++i){
if(sum[i]>0)add(S,i,sum[i]);
if(sum[i]<0)add(i,T,-sum[i]);
}
add(t,s,inf);
maxflow(S,T);
Can=e[tot].w,e[tot].w=e[tot^1].w=0,cout<<Can-maxflow(t,s);
return 0;
}
/*
此题本身为
有向无环图,可重复的最小路径覆盖问题
我们想要覆盖所有的边。
令每条边为 [1,+oo)
建超级源点和汇点 连所有点 [0,+oo)
有源汇
上下界
最小流
1.t->s 连inf 跑可行流
2.删掉inf边和可行流时的附加边。
3.跑 t->s的最大流
无源汇上下界可行流
建超级源点和汇点
先把每条边的下界连上,每条边剩下 r-l
如果一个点有多余流量则向汇点连,缺少流量则源点连向它
最终跑最大流 判断。
有源汇上下界可行流才可以跑出实际的流量,可行流量为 t->s inf边的使用流量
网络最大流中某边的使用流量等于该边反边的可行流量
*/