[模板] 最小费用最大流

一、题目

点此看题

二、解法

讲一种势能 ( t dijkstra) 的做法(简称势能算法),因为 ( t spfa) 在单次扩展的时候可能会被卡到 (O(nm)),而势能 ( t dijkstra) 的时间复杂度是严格的 (O(mlog n)),在一些扩展次数较小的毒瘤题中可能会用到。

势能算法的中心思路是化负权边为非负权边,我们设计势能函数 (h(x)) 来调整边权,这里的势能和物理中的定义是很相似的,也就是势能变化之和初末位置有关,而和路径无关。

(w'(u,v)=w(u,v)+h(u)-h(v)),不难发现最后跑出来的最短路要加上 (h(t)-h(s))

关键是如何使得 (w(u,v)+h(u)-h(v)geq0) 恒成立,设 (d(u))(s)(u) 真正的最短路,设 (dis(u))(s)(u) 通过转化后的边求出来的最短路,令 (h(s)=0),有 (dis(u)+h(u)=d(u))

如果我们再每次做完最短路之后让 (h(u)leftarrow d(u)) 是满足条件的,因为如果是原来的边那么显然 (d(u)-d(v)+w(u,v)geq 0),如果是新产生的取负的边那么 (d(u)=d(v)+w,(w>0) ightarrow d(u)-d(v)-w=0),新的边权就是 (0),也满足条件。那么每次我们把 (h(u)) 加上 (dis(u)) 就可以维护势能函数了。

时间复杂度 (O(flowcdot mlog n))

#include <cstdio>
#include <queue>
using namespace std;
const int M = 50005;
const int inf = 0x3f3f3f3f;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,s,t,tot,f[M],dis[M],fw[M],pre[M],lst[M],h[M];
struct edge
{
	int v,f,c,next;
}e[2*M];
struct node
{
	int u,c;
	bool operator < (const node &b) const
	{
		return c>b.c;
	}
};
void add(int u,int v,int F,int c)
{
	e[++tot]=edge{v,F,c,f[u]},f[u]=tot;
	e[++tot]=edge{u,0,-c,f[v]},f[v]=tot;
}
int bfs()
{
	for(int i=1;i<=n;i++) dis[i]=inf;
	fw[s]=inf;pre[s]=lst[s]=dis[s]=0;
	priority_queue<node> q;
	q.push(node{s,0});
	while(!q.empty())
	{
		node t=q.top();q.pop();int u=t.u;
		for(int i=f[u];i;i=e[i].next)
		{
			int v=e[i].v,c=h[u]-h[v]+e[i].c;
			if(dis[v]>dis[u]+c && e[i].f)
			{
				dis[v]=dis[u]+c;
				pre[v]=u;lst[v]=i;
				fw[v]=min(fw[u],e[i].f);
				q.push(node{v,dis[v]});
			}
		}
	}
	return dis[t]<inf;
}
signed main()
{
	n=read();m=read();s=read();t=read();tot=1;
	for(int i=1;i<=m;i++)
	{
		int u=read(),v=read(),f=read(),c=read();
		add(u,v,f,c);
	}
	int ans=0,flow=0;
	while(bfs())
	{
		int zy=t;
		flow+=fw[t];
		ans+=(dis[t]+h[t])*fw[t];
		while(zy!=s)
		{
			e[lst[zy]].f-=fw[t];
			e[lst[zy]^1].f+=fw[t];
			zy=pre[zy];
		}
		for(int i=1;i<=n;i++)
			h[i]+=dis[i];
	}
	printf("%d %d
",flow,ans);
}
原文地址:https://www.cnblogs.com/C202044zxy/p/15145143.html