码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 2245 SDOI 2011 工作安排 费用流

时间:2014-10-09 19:45:57      阅读:191      评论:0      收藏:0      [点我收藏+]

标签:bzoj   bzoj2245   sdoi2011   费用流   建图   

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


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

由于题目中满足那些分段函数是满足单调递增的性质的,所以就可以如下建图:

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   bzoj2245   sdoi2011   费用流   建图   

原文地址:http://blog.csdn.net/jiangyuze831/article/details/39933597

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!