网络流,费用流和二分图匹配模板

  • 网络流

  • Dinic

int head[N],p=1,S,T,n,m;
struct ss{int v,last,rl;}G[M<<1];
void add(int a,int b,int c){
	G[++p]=(ss){b,head[a],c};head[a]=p;
	G[++p]=(ss){a,head[b],0};head[b]=p;
}
int dis[N];
int bfs(int S,int T){
  memset(dis,0,sizeof(dis));
  queue<int> Q;dis[S]=1;Q.push(S);
  while(!Q.empty()){
    int u=Q.front();Q.pop();
    for(int i=head[u];i;i=G[i].last)
    if(G[i].rl>0&&dis[G[i].v]==0){
      dis[G[i].v]=dis[u]+1;
      Q.push(G[i].v);
    }
  }
  if(dis[T]!=0)return 1;
  else return 0;
}
int Augment(int a,int S,int T,int mi){
  if(a==T)return mi;
	int flow=0;
  for(int i=head[a];i;i=G[i].last)
  if((dis[G[i].v]==dis[a]+1)&&(G[i].rl!=0)){
    int ls=Augment(G[i].v,S,T,min(mi,G[i].rl));
		flow+=ls;mi-=ls;G[i].rl-=ls;G[i^1].rl+=ls;
    if(!mi)return flow;
  }
  return flow;
}
int Dinic(int S,int T){
	int ans=0,ls;
  while(bfs(S,T))ans+=Augment(S,S,T,inf);
  return ans;
}
  • ISAP

int head[N],p=1,S,T,n,m;
struct ss{int v,last;int rl;}G[M<<1];
void add(int a,int b,int c){
	G[++p]=(ss){b,head[a],c};head[a]=p;
	G[++p]=(ss){a,head[b],0};head[b]=p;
}
int dis[N],cur[N],num[N];
void bfs(int T){
	memset(dis,0,sizeof(dis));
	memset(num,0,sizeof(num));
	++num[dis[T]=1];
	memcpy(cur,head,sizeof(head));
	queue<int> Q;Q.push(T);
	while(!Q.empty()){
		int u=Q.front();Q.pop();
		for(int i=head[u];i;i=G[i].last)if(!dis[G[i].v])
		{++num[dis[G[i].v]=dis[u]+1];Q.push(G[i].v);}
	}
}
int Augment(int a,int S,int T,int mi){
	if(a==T)return mi;
	int flow=0;
	for(int i=cur[a];i;i=G[i].last)if(dis[G[i].v]==dis[a]-1){
		int ls=Augment(G[i].v,S,T,min(mi,G[i].rl));
		flow+=ls;mi-=ls;G[i].rl-=ls;G[i^1].rl+=ls;
		if(!mi)return flow;
	}
	if(!(--num[dis[a]]))dis[S]=n+1;
	++num[++dis[a]];cur[a]=head[a];
	return flow;
}
int ISAP(int S,int T){
	bfs(T);
	int ret=Augment(S,S,T,inf);
	while(dis[S]<=n)ret+=Augment(S,S,T,inf);
	return ret;
}
  • 费用流(最小费用最大流)

  • ZKW

int head[N],p=1,S,T,n,m,k;
struct ss{int v,last;int rl,w;}G[M<<1];
void add(int a,int b,int c,int d){
	G[++p]=(ss){b,head[a],c,d};head[a]=p;
	G[++p]=(ss){a,head[b],0,-d};head[b]=p;
}
queue<int> Q;
int dis[N],Mincost,Maxflow;
bool used[N];
bool vis[N];
bool SPFA(int S,int T){
	for(int i=0;i<N;i++)dis[i]=inf,vis[i]=0;
	dis[T]=0,vis[T]=1;
	Q.push(T);
	while(!Q.empty()){
		int u=Q.front();Q.pop();vis[u]=0;
		for(int i=head[u];i;i=G[i].last)
		if(G[i^1].rl>0&&dis[G[i].v]>dis[u]-G[i].w){
			dis[G[i].v]=dis[u]-G[i].w;
			if(!vis[G[i].v])
			Q.push(G[i].v),vis[G[i].v]=1;
		}
	}
	return dis[S]<inf;
}
int Augment(int a,int S,int T,int mi){
	used[a]=1;
	if(a==T)return mi;
  int flow=0;
  for(int i=head[a];i;i=G[i].last)
	if(!used[G[i].v]&&G[i].rl&&dis[a]-G[i].w==dis[G[i].v]){
	  int ls=Augment(G[i].v,S,T,min(G[i].rl,mi));
	  Mincost+=ls*G[i].w,mi-=flow,G[i].rl-=ls,G[i^1].rl+=ls,flow+=ls;
	  if(!mi)return flow;
  }
  return flow;
}
void ZKW(int S,int T){
	Maxflow=Mincost=0;
	while(SPFA(S,T)){
		used[T]=1;
    while(used[T]){
      memset(used,0,sizeof(used));
      Maxflow+=Augment(S,S,T,inf);
    }
	}
}
  • 二分图匹配

  • Hungary


bool used[N<<1];
int n,m,e,ans;
int head[N],p;
struct ss{int v,last;}G[N*N];
void add(int a,int b)
{G[++p].v=b;G[p].last=head[a];head[a]=p;}
int match[N<<1];
bool dfs(int u){
	for(int i=head[u];i;i=G[i].last)if(!used[G[i].v]){
		used[G[i].v]=1;
		if(!match[G[i].v]||dfs(match[G[i].v]))
		{match[G[i].v]=u;return 1;}
	}
	return 0;
}
int Hungary(int n){
	int ans=0;
	for(int i=1;i<=n;i++){
		memset(used,0,sizeof(used));
		if(dfs(i))ans++;
	}
	return ans;
}
  • Kuhn Munkres(带权)

int head[N],p;
struct ss{int v,last,w;}G[N*N];
void add(int a,int b,int c)
{G[++p].v=b;G[p].last=head[a];G[p].w=c;head[a]=p;}
bool usem[N<<1],usen[N<<1];
int match[N<<1];
int maxn[N<<1],maxm[N<<1];
int slack[N<<1];
bool dfs(int u){
  usen[u]=1;
  for(int i=head[u];i;i=G[i].last){
    if(usem[G[i].v])continue;
    int gap=maxn[u]+maxm[G[i].v]-G[i].w;
    if(gap==0){
      usem[G[i].v]=1;
      if(match[G[i].v]==0||dfs(match[G[i].v]))
			{match[G[i].v]=u;return 1;}
    } 
		else slack[G[i].v]=min(slack[G[i].v],gap);
  }
  return 0;
}
int Kuhn_Munkres(int n){
	memset(match,0,sizeof(match));
	memset(maxm,0,sizeof(maxm));
	for(int u=1;u<=n;u++){
		maxn[u]=-inf;
		for(int i=head[u];i;i=G[i].last)
		maxn[u]=max(maxn[u],G[i].w);
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++)slack[j]=inf;
		while(1){
			memset(usem,0,sizeof(usem));
			memset(usen,0,sizeof(usen));
			if(dfs(i))break;
			int a=inf;
      for(int j=1;j<=m;j++)
      if(!usem[j])a=min(a,slack[j]);
      for(int j=1;j<=n;j++)
        if(usen[j])maxn[j]-=a;
      for(int j=1;j<=m;j++)
        if(usem[j])maxm[j]+=a;
		}
	}
	int res=0;
  for(int u=1;u<=n;u++){
		for(int i=head[u];i;i=G[i].last)
		if(match[G[i].v]==u)
		res+=G[i].w;
	}
  return res;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值