【模板】最小费用最大流【费用流】

题目大意:

给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。


思路:

既然是模板题,那么数据肯定很水
EK+SPFAEK+SPFA都过了。
费用流其实就是最大流改一个SPFASPFA而已,很简单。


代码:

#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#define Inf 2147483647
using namespace std;

int n,m,s,t,x,y,c,w,k,minn,ans,sum,dis[10001],head[250011];
bool vis[10001];

struct edge  //邻接表
{
	int next,to,c,w;
}e[250011];

struct pre  //记录路径
{
	int fa,e;
}p[250011];

void add(int from,int to,int c,int w)  //建模
{
	k++;
	e[k].to=to;
	e[k].c=c;
	e[k].w=w;
	e[k].next=head[from];
	head[from]=k;
}

bool spfa()  //最短路不解释
{
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	memset(p,0,sizeof(p));
	queue<int> q;
	q.push(s);
	vis[s]=1;
	dis[s]=0;
	while (q.size())
	{
		int u=q.front();
		q.pop();
		vis[u]=0;
		for (int i=head[u];i;i=e[i].next)
		{
			int v=e[i].to;
			int w=e[i].w;
			if (e[i].c&&dis[v]>dis[u]+w)
			{
				dis[v]=dis[u]+w;
				p[v].fa=u;
				p[v].e=i;
				if (!vis[v])
				{
					vis[v]=1;
					q.push(v);
				}
			}
		}
	}
	return dis[t]!=0x3f3f3f3f;
}

int main()
{
	k=1;
	scanf("%d%d%d%d",&n,&m,&s,&t);
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d%d%d",&x,&y,&c,&w);
		add(x,y,c,w);
		add(y,x,0,-w);  //反向变的费用为正向边的相反数
	}
	while (spfa())
	{
		minn=Inf;
		for (int i=t;i!=s;i=p[i].fa)
		 minn=min(minn,e[p[i].e].c);  //求最小流量
		for (int i=t;i!=s;i=p[i].fa)
		{
			e[p[i].e].c-=minn;  //正向边
			e[p[i].e^1].c+=minn;  //反向边
		}
		ans+=minn;  //最大流
		sum=sum+minn*dis[t];  //最小花费
	}
	printf("%d %d\n",ans,sum);
	return 0;
}
posted @ 2018-08-11 09:21  全OI最菜  阅读(93)  评论(0编辑  收藏  举报