洛谷P3381 Dijkstra版费用流

https://www.luogu.com.cn/problem/P3381

鉴于spfa很容易被卡,所以学了一手dij跑费用流

具体参考:https://www.luogu.com.cn/blog/Mogician/Network-Flow-Guide,虽然有个小地方少了个负号,不过还好

区别就是把(u->v)边权变成cost+h[u]-h[v],先用spfa算出dis当h[i],然后每次跑完mcf,由于负权边的容量可能增加能选了,就要h[i]+=dis[i]这样动态维护,就能保证每条边都是正的

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int> p;

const int maxl=5010;
const int maxm=1e5+10;
const ll inf=1ll<<60;

int n,m,S,T,cnt;
ll ans,flow;
int ehead[maxl],frm[maxl];
ll dis[maxl],h[maxl];
struct ed
{
	int frm,to,nxt;ll w,c;
}e[maxm<<1];
bool in[maxl];

inline void add(int u,int v,ll w,ll c)
{
	e[++cnt].to=v;e[cnt].frm=u;
	e[cnt].w=w;e[cnt].c=c;
	e[cnt].nxt=ehead[u];ehead[u]=cnt;	
}

inline void prework()
{
	scanf("%d%d%d%d",&n,&m,&S,&T);
	int u,v;ll w,c;cnt=1;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%lld%lld",&u,&v,&w,&c);
		add(u,v,w,c);add(v,u,0,-c);
	}
}

inline void spfa()
{
	queue<int> q;
	for(int i=1;i<=n;i++)
		h[i]=inf,in[i]=false;
	q.push(S);h[S]=0;in[S]=true;
	int u,v;
	while(!q.empty())
	{
		u=q.front();q.pop();in[u]=false;
		for(int i=ehead[u];i;i=e[i].nxt)
		if(e[i].w)
		{
			v=e[i].to;
			if(h[v]>h[u]+e[i].c)
			{
				h[v]=h[u]+e[i].c;
				if(!in[v])
				{
					q.push(v);
					in[v]=true;
				}
			}
		}
	}
}

inline bool dij()
{
	priority_queue<p,vector<p>,greater<p> >q;
	for(int i=1;i<=n;i++)
		dis[i]=inf,in[i]=false,frm[i]=0;
	dis[S]=0;q.push({dis[S],S});
	int u,v;p d;
	while(!q.empty())
	{
		d=q.top();q.pop();
		u=d.second;
		if(in[u] || dis[u]!=d.first)
			continue;
		in[u]=true;
		for(int i=ehead[u];i;i=e[i].nxt)
		if(e[i].w)
		{
			v=e[i].to;
			if(in[v] || dis[v]<=dis[u]+e[i].c+h[u]-h[v])
				continue;
			frm[v]=i;
			dis[v]=dis[u]+e[i].c+h[u]-h[v];
			q.push({dis[v],v});
		}
	}
	return dis[T]<inf;
}

inline void mcf()
{
	int i=T;ll x=inf;
	i=frm[T];
	while(i>0)
	{
		x=min(x,e[i].w);
		i=frm[e[i].frm];
	}
	i=frm[T];
	while(i>0)
	{
		e[i].w-=x;
		e[i^1].w+=x;
		i=frm[e[i].frm];
	}
	flow+=x;
	ans+=x*(dis[T]+h[T]);
}

inline void mainwork()
{
	ans=0;
	spfa();
	while(dij())
	{
		mcf(); 
		for(int i=1;i<=n;i++)
			h[i]=min(inf,h[i]+dis[i]);
	}
}

inline void print()
{
	printf("%lld %lld",flow,ans);
}

int main()
{
	prework();
	mainwork();
	print();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/107374093