BZOJ 2245 SDOI 2011 工作安排 费用流

来源:互联网 发布:在淘宝上如何买春药 编辑:程序博客网 时间:2024/05/22 00:35

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


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

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

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;}


0 0
原创粉丝点击