BZOJ 2245 SDOI 2011 工作安排 费用流

Posted zhchoutai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 2245 SDOI 2011 工作安排 费用流相关的知识,希望对你有一定的参考价值。

题目大意:有一些商品须要被制造。有一些员工。每个员工会做一些物品,然而这些员工做物品越多,他们的愤慨值越大,这满足一个分段函数。给出哪些员工能够做哪些东西,给出这些分段函数,求最小的愤慨值以满足须要被制造的商品。


思路:费用流。

我写的朴素费用流好像非常慢,有时间学一学费用流的多路增广。

因为题目中满足那些分段函数是满足单调递增的性质的,所以就能够例如以下建图:

S->每一个人,费用0,流量INF

每一个商品->T,费用0,流量为须要改商品的数量

对于每一个人虚拟建n个节点(n<=5)

每一个人->虚拟节点。费用为分段函数的值,流量INF

每一个人的虚拟节点->那个人可以做出的商品。费用0。流量INF

这样跑EK费用流就能够了。


CODE:


#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 2010
#define MAXE 600010
#define INF 0x3f3f3f3f
#define S 0
#define T (MAX - 1)
using namespace std;

int persons,staffs;
bool work[300][300];

int head[MAX],total = 1;
int next[MAXE],aim[MAXE],flow[MAXE],cost[MAXE];

int src[MAX];

int f[MAX],p[MAX],from[MAX];
bool v[MAX];

inline void Add(int x,int y,int f,int c);
long long EdmondsKarp();
bool SPFA();

int main()
{
	cin >> persons >> staffs;
	for(int i = 1;i <= persons; ++i) {
		Add(S,i,INF,0);
		Add(i,S,0,0);
	}
	for(int x,i = 1;i <= staffs; ++i) {
		scanf("%d",&x);
		Add(i + persons,T,x,0);
		Add(T,i + persons,0,0);
	}
	for(int i = 1;i <= persons; ++i)
		for(int j = 1;j <= staffs; ++j)
			scanf("%d",&work[i][j]);
	int now = persons + staffs;
	for(int cnt,i = 1;i <= persons; ++i) {
		scanf("%d",&cnt);
		for(int j = 1;j <= cnt; ++j)
			scanf("%d",&src[j]);
		src[cnt + 1] = INF;
		for(int x,j = 1;j <= cnt + 1; ++j) {
			scanf("%d",&x);
			Add(i,++now,src[j] - src[j - 1],x);
			Add(now,i,src[j] - src[j - 1],-x);
			for(int k = 1;k <= staffs; ++k)
				if(work[i][k]) {
					Add(now,persons + k,INF,0);
					Add(persons + k,now,0,0);
				}
		}
	}
	cout << EdmondsKarp() << endl;
	return 0;
}

inline void Add(int x,int y,int f,int c)
{
	next[++total] = head[x];
	aim[total] = y;
	flow[total] = f;
	cost[total] = c;
	head[x] = total; 
}

long long EdmondsKarp()
{
	long long re = 0;
	while(SPFA()) {
		int remain = INF;
		for(int i = T;i != S;i = from[i])
			remain = min(remain,flow[p[i]]);
		for(int i = T;i != S;i = from[i]) {
			flow[p[i]] -= remain;
			flow[p[i]^1] += remain;
		}
		re += f[T] * remain;
	}
	return re;
}

bool SPFA()
{
	static queue<int> q;
	while(!q.empty())	q.pop();
	q.push(S);
	memset(f,0x3f,sizeof(f));
	memset(v,false,sizeof(v));
	f[S] = 0;
	while(!q.empty()) {
		int x = q.front(); q.pop();
		v[x] = false;
		for(int i = head[x];i;i = next[i])
			if(flow[i] && f[aim[i]] > f[x] + cost[i]) {
				f[aim[i]] = f[x] + cost[i];
				if(!v[aim[i]]) {
					v[aim[i]] = true;
					q.push(aim[i]);
				}
				from[aim[i]] = x;
				p[aim[i]] = i;
			}
	}
	return f[T] != 0x3f3f3f3f;
}


以上是关于BZOJ 2245 SDOI 2011 工作安排 费用流的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 2245[SDOI2011]工作安排

BZOJ 2245 SDOI 2011 工作安排 费用流

BZOJ2245 SDOI2011 工作安排 费用流

bzoj 2245 [SDOI2011]工作安排最小费用最大流

bzoj2245[SDOI2011]工作安排 费用流

BZOJ2245 [SDOI2011]工作安排 费用流