标签: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 bzoj2245 sdoi2011 费用流 建图
原文地址:http://blog.csdn.net/jiangyuze831/article/details/39933597