最小费用最大流

link

也是一道模板题,和最大流是一个道理。我学的这种写法是Dinic的改进版,给每条边维护两个边权,一个是流量,一个是费用。每次对费用用SPFA跑一个最短路,然后就着这个最短路去跑一次Dinic。唯一需要注意的是反边。考虑到反边的本质是让某条旧路径放弃原有的那一段路不走了,所以费用应该会减少,建边时对应的费用边权赋值为费用的相反数即可。

#include<cstdio>
#include<cstring>
#include<queue>
//#define zczc
using namespace std;
const int N=5010;
const int M=50010;
const int inf=1e9;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}
inline int min(int s1,int s2){
	return s1<s2?s1:s2;
}

int m,n,s,t;
struct edge{
	int t,v1,v2,next;
}e[M<<1];
int head[N],h[N],esum=1;
inline void add(int fr,int to,int val1,int val2){
	esum++;e[esum].t=to;e[esum].v1=val1;e[esum].v2=val2;e[esum].next=head[fr];
	head[fr]=esum;return;
}

queue<int>qu;
bool inq[N],vis[N];
int dis[N],q[N],l,r;
bool check(){
	memset(dis,0x3f,sizeof(dis));
	memset(inq,false,sizeof(inq));
	memset(vis,false,sizeof(vis));
	dis[s]=0;qu.push(s);
	while(!qu.empty()){
		int wh=qu.front();qu.pop();inq[wh]=false;
		for(int i=head[wh],th;i;i=e[i].next){
			if(e[i].v1<=0||dis[wh]+e[i].v2>=dis[th=e[i].t])continue;
			dis[th]=dis[wh]+e[i].v2;if(!inq[th])inq[th]=true,qu.push(th);
		}
	}
	return dis[t]<inf;
}

int cc;
int dfs(int wh,int val){
	if(wh==t)return cc+=val*dis[wh],val;
	vis[wh]=true;int used=0;
	for(int i=head[wh],th;i;i=e[i].next){
		if(e[i].v1==0||vis[th=e[i].t]||dis[wh]+e[i].v2!=dis[th])continue;
		int now=dfs(th,min(val-used,e[i].v1));
		if(now)e[i].v1-=now,e[i^1].v1+=now,used+=now;
		if(used==val)break;
	}
	return vis[wh]=used!=val,used;
}

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	int s1,s2,s3,s4;
	read(m);read(n);read(s);read(t);
	for(int i=1;i<=n;i++){
		read(s1);read(s2);read(s3);read(s4); 
		add(s1,s2,s3,s4);add(s2,s1,0,-s4);
	}
	
	int ans=0;
	while(check())ans+=dfs(s,inf);
	printf("%d %d",ans,cc);
	
	return 0;
}
posted @   Feyn618  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示