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


  • 相关阅读:
    蛇形填数字 (附书上例题答案)
    排列 (C++实现)
    分数化小数(C++)
    Operating System 1.2 什么是操作系统
    Python知识点入门笔记——基本控制流程
    Python知识点入门笔记——基本运算和表达式
    Python知识点入门笔记——Python的基本数据类型
    网络架构遵循原则
    浏览器输入网址后发生了这些
    JAVA解析XML有哪几种方法?并简述各自的优缺点
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/7131231.html
Copyright © 2020-2023  润新知