洛谷- P3381 【模板】最小费用最大流(板子!!)

题目链接:https://www.luogu.org/problemnew/show/P3381

题目描述

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

输入输出格式

输入格式:

第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。

接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。

输出格式:

一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。

输入输出样例

输入样例#1: 复制

4 5 4 3
4 2 30 2
4 3 20 3
2 3 20 1
2 1 30 9
1 3 40 5

输出样例#1: 复制

50 280

说明

时空限制:1000ms,128M

(BYX:最后两个点改成了1200ms)

数据规模:

对于30%的数据:N<=10,M<=10

对于70%的数据:N<=1000,M<=1000

对于100%的数据:N<=5000,M<=50000

样例说明:

如图,最优方案如下:

第一条流为4-->3,流量为20,费用为3*20=60。

第二条流为4-->2-->3,流量为20,费用为(2+1)*20=60。

第三条流为4-->2-->1-->3,流量为10,费用为(2+9+5)*10=160。

故最大流量为50,在此状况下最小费用为60+60+160=280。

故输出50 280。

题意很清晰,还给了解释唯恐不会写这个水题(笑)

题目上说的很明确,这是个最小费用最大流的模板题,上网查一下板子,理解一下,spfa直接就过了,给人自信心

ac:

#include<stdio.h>
#include<string.h>  
#include<math.h>  
  
#include<map>   
//#include<set>
#include<deque>  
#include<queue>  
#include<stack>  
#include<bitset> 
#include<string>  
#include<fstream>
#include<iostream>  
#include<algorithm>  
using namespace std;  

#define ll long long  
#define INF 0x3f3f3f3f  
#define mod 998244353
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b) 
#define clean(a,b) memset(a,b,sizeof(a))// 水印 
//std::ios::sync_with_stdio(false);


struct node{
	int v,w,cost,nxt;
	node(int _v=0,int _w=0,int _cost=0,int _nxt=0):
    v(_v),w(_w),cost(_cost),nxt(_nxt){}
}edge[100010];
int head[100010],e;
int pre[100010],last[100010],dis[100010],flow[100010];
//前驱			前一条边	最小花费	原点到此处的流量 
int vis[100010];
int maxw,mincost;
int n,m,s,t;

void add(int u,int v,int w,int cost)
{
	edge[e]=node(v,w,cost,head[u]);
	head[u]=e++;
}

bool spfa()
{
	clean(dis,INF);
	clean(flow,INF);
	clean(vis,0);
	queue<int> que;
	que.push(s);
	vis[s]=1;
	dis[s]=0;//最小花费为0 
	pre[t]=-1;//目前 终点没有前驱节点 
	while(que.size())
	{
		int u=que.front();
		que.pop();
		vis[u]=0;
		for(int i=head[u];i+1;i=edge[i].nxt)
		{
			if(edge[i].w>0&&dis[edge[i].v]>dis[u]+edge[i].cost)
			{
				dis[edge[i].v]=dis[u]+edge[i].cost;//花费 
				pre[edge[i].v]=u;//该点的前驱是u		用于接下来的遍历 
				last[edge[i].v]=i;//该点的前一条边是i 
				flow[edge[i].v]=min(flow[u],edge[i].w);//最小联通 
				if(vis[edge[i].v]==0)
				{
					vis[edge[i].v]=1;
					que.push(edge[i].v);
				}
			}
		}
	}
	if(pre[t]==-1)
		return 0;
	return 1;
}

void MCMF()
{
	while(spfa())//最小费用 
	{
		int u=t;
		maxw+=flow[t];
		mincost+=dis[t]*flow[t];
		while(u!=s)//最大流 
		{
			edge[last[u]].w-=flow[t];
			edge[last[u]^1].w+=flow[t];
			u=pre[u];
		}
	}
	cout<<maxw<<" "<<mincost<<endl;//ans 
}

int main()
{
	clean(head,-1),e=0;
	cin>>n>>m>>s>>t;
	int a,b,w,cost;
	for(int i=0;i<m;++i)
	{
		cin>>a>>b>>w>>cost;
		add(a,b,w,cost);
		add(b,a,0,-cost);
	}
	MCMF();
}

猜你喜欢

转载自blog.csdn.net/qq_40482358/article/details/81877295