最小费用流模板

思路:每次先以价值为边权走一遍SPFA,沿最短路增广。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MAXN=501;
const LL MAXM=3e4+10;
const LL INF=0x3f3f3f3f;

LL n,m,s,t,cnt;
LL head[MAXN],vis[MAXN],work[MAXN],dis[MAXN];
LL nxt[MAXM],to[MAXM],w[MAXM],c[MAXM];
queue<LL> q;
LL cost;
pair<LL,LL> ans;

void Add(LL x,LL y,LL f,LL h)
{
	nxt[cnt]=head[x];
	head[x]=cnt;
	to[cnt]=y;
	w[cnt]=f;
	c[cnt]=h;
	cnt++;
}

void add(LL x,LL y,LL f,LL h)
{
	Add(x,y,f,h);
	Add(y,x,0,-h);
}

bool SPFA()
{
	memset(dis,INF,sizeof(dis));
	memset(work,0,sizeof(work));
	dis[s]=0;
	while(!q.empty())
	  q.pop();
	q.push(s);
	while(!q.empty())
	{
		LL u=q.front();
		vis[u]=0;
		q.pop();
		for(LL i=head[u];i!=-1;i=nxt[i])
		{
			LL v=to[i];
			if(dis[v]>dis[u]+c[i]&&w[i])
			{
				dis[v]=dis[u]+c[i];
				if(!vis[v])
				{
					vis[v]=1;
					q.push(v);
				}
			}
		}
	}
	return dis[t]<INF;
}

LL dfs(LL u,LL dist)
{
	if(u==t)
	{
		cost+=dist*dis[t];
		return dist;
	}
	work[u]=1;
	LL res=0;
	for(LL i=head[u];i!=-1;i=nxt[i])
	{
		LL v=to[i];
		if(dis[v]==dis[u]+c[i]&&!work[v]&&w[i])
		{
			LL di=dfs(v,min(dist-res,w[i]));
			if(di)
			{
				w[i]-=di;
				w[i^1]+=di;
				res+=di;
				if(res==dist)
				  break;
			}
		}
	}
	return res;
}

pair<LL,LL> dinic()
{
	LL maxf=0;
	while(SPFA())
	  maxf+=dfs(s,INF);
	return make_pair(maxf,cost);
}

int main()
{
	memset(head,-1,sizeof(head));
	memset(nxt,-1,sizeof(nxt));
	cin>>n>>m;
	s=1,t=n;
	for(LL i=1;i<=m;++i)
	{
		LL x,y,f,h;
		cin>>x>>y>>f>>h;
		add(x,y,f,h);
	}
	pair<LL,LL> ans1=dinic();
	cout<<ans1.first<<" "<<ans1.second;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/g21glf/article/details/82890681