Libre 6012 「网络流 24 题」分配问题 (网络流,费用流)

Libre 6012 「网络流 24 题」分配问题 (网络流,费用流)

Description

有n件工作要分配给n个人做。第i个人做第j件工作产生的效益为\(c_{ij}\)。试设计一个将n件工作分配给n个人做的分配方案,使产生的总效益最大。
对于给定的n件工作和n个人,计算最优分配方案和最差分配方案。

Input

第1 行有1 个正整数n,表示有n件工作要分配给n 个人做。
接下来的n 行中,每行有n 个整数\(c_{ij}\),1≤i≤n,1≤j≤n,表示第i 个人做第j件工作产生的效益为\(c_{ij}\)

Output

将计算出的最小总效益和最大总效益输出

Sample Input

5
2 2 2 1 2
2 3 1 2 4
2 0 1 1 1
2 3 4 3 3
3 2 1 2 1

Sample Output

5
14

Http

Libre:https://loj.ac/problem/6012

Source

网络流,费用流

解决思路

此题的网络流做法还是比较明显的。对于每一个人,从源点连边容量为1代价为0,而对于每一项工作,连到汇点容量为1,代价为0。对于每一个\(c_{ij}\),连接人i和工作j,容量为1代价为\(c_{ij}\)。然后分别跑最小费用最大流和最大费用最大流即可。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int maxN=300;
const int maxM=maxN*maxN*4;
const int inf=2147483647;

class Edge
{
public:
	int u,v,cost,flow;
};

int n;
int cnt=-1;
int Head[maxN];
int Next[maxM];
Edge E[maxM];
int Dist[maxN];
bool inqueue[maxN];
int Q[maxM];
int Path[maxN];
int Flow[maxN];
int G[maxN][maxN];

void Add_Edge(int u,int v,int cost,int flow);
bool spfa1();
bool spfa2();

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			scanf("%d",&G[i][j]);
	//Q1最小费用最大流
	cnt=-1;
	memset(Head,-1,sizeof(Head));
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			Add_Edge(i,j+n,G[i][j],1);
	for (int i=1;i<=n;i++)
	{
		Add_Edge(0,i,0,1);
		Add_Edge(i+n,n*2+1,0,1);
	}
	int Ans=0;
	while (spfa1())
	{
		int now=n*2+1;
		int last=Path[now];
		while (now!=0)
		{
			E[last].flow-=Flow[n*2+1];
			E[last^1].flow+=Flow[n*2+1];
			now=E[last].u;
			last=Path[now];
		}
		Ans+=Dist[n*2+1]*Flow[n*2+1];
	}
	cout<<Ans<<endl;
	//Q2最大费用最大流
	cnt=-1;
	memset(Head,-1,sizeof(Head));
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			Add_Edge(i,j+n,G[i][j],1);
	for (int i=1;i<=n;i++)
	{
		Add_Edge(0,i,0,1);
		Add_Edge(i+n,n*2+1,0,1);
	}
	Ans=0;
	while (spfa2())
	{
		int now=n*2+1;
		int last=Path[now];
		while (now!=0)
		{
			E[last].flow-=Flow[n*2+1];
			E[last^1].flow+=Flow[n*2+1];
			now=E[last].u;
			last=Path[now];
		}
		Ans+=Dist[n*2+1]*Flow[n*2+1];
	}
	cout<<Ans<<endl;
	return 0;
}

void Add_Edge(int u,int v,int cost,int flow)
{
	cnt++;
	Next[cnt]=Head[u];
	Head[u]=cnt;
	E[cnt].u=u;
	E[cnt].v=v;
	E[cnt].cost=cost;
	E[cnt].flow=flow;

	cnt++;
	Next[cnt]=Head[v];
	Head[v]=cnt;
	E[cnt].u=v;
	E[cnt].v=u;
	E[cnt].flow=0;
	E[cnt].cost=-cost;
}

bool spfa1()
{
	for (int i=0;i<=n*2+1;i++)
		Dist[i]=inf;
	memset(inqueue,0,sizeof(inqueue));
	int h=1,t=0;
	Q[1]=0;
	inqueue[0]=1;
	Dist[0]=0;
	Flow[0]=inf;
	do
	{
		t++;
		int u=Q[t];
		inqueue[u]=0;
		for (int i=Head[u];i!=-1;i=Next[i])
		{
			int v=E[i].v;
			if ((E[i].flow>0)&&(Dist[v]>Dist[u]+E[i].cost))
			{
				Dist[v]=Dist[u]+E[i].cost;
				Flow[v]=min(Flow[u],E[i].flow);
				Path[v]=i;
				if (inqueue[v]==0)
				{
					h++;
					Q[h]=v;
					inqueue[v]=1;
				}
			}
		}
	}
	while (h!=t);
	if (Dist[n*2+1]==inf)
		return 0;
	return 1;
}

bool spfa2()
{
	for (int i=0;i<=n*2+1;i++)
		Dist[i]=-inf;
	memset(inqueue,0,sizeof(inqueue));
	int h=1,t=0;
	Q[1]=0;
	inqueue[0]=1;
	Dist[0]=0;
	Flow[0]=inf;
	do
	{
		t++;
		int u=Q[t];
		inqueue[u]=0;
		for (int i=Head[u];i!=-1;i=Next[i])
		{
			int v=E[i].v;
			if ((E[i].flow>0)&&(Dist[v]<Dist[u]+E[i].cost))
			{
				Dist[v]=Dist[u]+E[i].cost;
				Flow[v]=min(Flow[u],E[i].flow);
				Path[v]=i;
				if (inqueue[v]==0)
				{
					h++;
					Q[h]=v;
					inqueue[v]=1;
				}
			}
		}
	}
	while (h!=t);
	if (Dist[n*2+1]==-inf)
		return 0;
	return 1;
}
posted @ 2017-08-08 11:54  SYCstudio  阅读(261)  评论(0编辑  收藏  举报