zoukankan      html  css  js  c++  java
  • [BZOJ1061][Noi2008]志愿者招募

    [BZOJ1061][Noi2008]志愿者招募

    试题描述

    申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管。布布刚上任就遇到了一个难

    题:为即将启动的奥运新项目招募一批短期志愿者。经过估算,这个项目需要N 天才能完成,其中第i 天至少需要
    Ai 个人。 布布通过了解得知,一共有M 类志愿者可以招募。其中第i 类可以从第Si 天工作到第Ti 天,招募费用
    是每人Ci 元。新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这
    并不是他的特长!于是布布找到了你,希望你帮他设计一种最优的招募方案。

    输入

    第一行包含两个整数N, M,表示完成项目的天数和可以招募的志愿者的种类。 接下来的一行中包含N 个非负

    整数,表示每天至少需要的志愿者人数。 接下来的M 行中每行包含三个整数Si, Ti, Ci,含义如上文所述。为了
    方便起见,我们可以认为每类志愿者的数量都是无限多的。

    输出

    仅包含一个整数,表示你所设计的最优方案的总费用。

    输入示例

    3 3
    2 3 4
    1 2 2
    2 3 5
    3 3 2

    输出示例

    14

    数据规模及约定

    1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均 不超过2^31-1。

    题解

    NOI的题目就是好。。。既能学新姿势还能轻松A掉。。。

    这是一道费用流的题目,但是它的解题思路是基于流量平衡的。这类题可以搜集题目中的限制条件列出等式,转化成 A - B = 0 的形式,那么将该等式作为一个节点,A 就是流入的流量,B 即为流出的流量。

    详细题解:https://www.byvoid.com/blog/noi-2008-employee/

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <stack>
    #include <vector>
    #include <queue>
    #include <cstring>
    #include <string>
    #include <map>
    #include <set>
    using namespace std;
    
    const int BufferSize = 1 << 16;
    char buffer[BufferSize], *Head, *tail;
    inline char Getchar() {
        if(Head == tail) {
            int l = fread(buffer, 1, BufferSize, stdin);
            tail = (Head = buffer) + l;
        }
        return *Head++;
    }
    int read() {
        int x = 0, f = 1; char c = Getchar();
        while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
        while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
        return x * f;
    }
    
    #define maxn 1010
    #define maxm 24012
    #define oo 2147483647
    #define ool 1ll << 60
    #define LL long long
    struct Edge { int from, to, flow, cost; } ;
    struct ZKW {
    	int n, m, s, t, head[maxn], next[maxm];
    	Edge es[maxm];
    	LL d[maxn];
    	bool vis[maxn];
    	LL ans, cost;
    	void init(int nn) {
    		n = nn; m = 0;
    		memset(head, -1, sizeof(head));
    		return ;
    	}
    	void AddEdge(int a, int b, int c, int d) {
    		es[m] = (Edge){ a, b, c, d }; next[m] = head[a]; head[a] = m++;
    		es[m] = (Edge){ b, a, 0, -d }; next[m] = head[b]; head[b] = m++;
    		return ;
    	}
    	bool BFS() {
    		for(int i = 1; i <= n; i++) d[i] = ool;
    		d[t] = 0;
    		deque <int> Q; Q.push_front(t);
    		while(!Q.empty()) {
    			int u = Q.front(); Q.pop_front();
    			for(int i = head[u]; i != -1; i = next[i]) {
    				Edge& e = es[i^1];
    				if(e.flow && d[e.from] > d[u] + e.cost) {
    					d[e.from] = d[u] + e.cost;
    					if(Q.empty() || d[e.from] <= d[Q.front()]) Q.push_front(e.from);
    					else Q.push_back(e.from);
    				}
    			}
    		}
    		if(d[s] == ool) return 0;
    		for(int i = 0; i < m; i++) es[i].cost += d[es[i].to] - d[es[i].from];
    		cost += d[s];
    		return 1;
    	}
    	int DFS(int u, int a) {
    		if(u == t || !a){ ans += cost * a; return a; }
    		int flow = 0, f;
    		vis[u] = 1;
    		for(int i = head[u]; i != -1; i = next[i]) {
    			Edge& e = es[i];
    			if(!vis[e.to] && !e.cost && (f = DFS(e.to, min(a, e.flow)))) {
    				flow += f; a -= f;
    				e.flow -= f; es[i^1].flow += f;
    				if(!a) return flow;
    			}
    		}
    		return flow;
    	}
    	int MaxFlow(int ss, int tt) {
    		s = ss; t = tt;
    		int flow = 0, f;
    		while(BFS())
    			do {
    				memset(vis, 0, sizeof(vis));
    				f = DFS(s, oo);
    				flow += f;
    			} while(f);
    		return flow;
    	}
    } sol;
    
    int main() {
    	int n = read(), m = read();
    	sol.init(n + 3); int s = n + 2, t = n + 3;
    	int lastA = 0, A;
    	for(int i = 1; i <= n; i++) {
    		A = read();
    		if(A - lastA > 0) sol.AddEdge(s, i, A - lastA, 0);
    		else sol.AddEdge(i, t, lastA - A, 0);
    		sol.AddEdge(i + 1, i, oo, 0);
    		lastA = A;
    	}
    	sol.AddEdge(n + 1, t, A, 0);
    	for(int i = 1; i <= m; i++) {
    		int x = read(), y = read(), c = read();
    		sol.AddEdge(x, y + 1, oo, c);
    	}
    	
    	sol.MaxFlow(s, t);
    	printf("%lld
    ", sol.ans);
    	
    	return 0;
    }
    /*
    3 3
    2 3 4
    1 2 2
    2 3 5
    3 3 2
    */
    

    这个题还有一个不用线性规划的做法:我们跑可行流。

    对于每一天,流量下界为每天需要的志愿者人数,然后对于一个从第 s 天到第 t 天的志愿者,从这个志愿者向第 s 天连边(容量无穷费用为该志愿者的费用),然后从第 t 天向该志愿者连边(容量无穷费用为 0)。

    我的代码搞了一个小优化,每天没有拆点,而是把一条边看成一天,所以加边成环时会有一些小边界问题要考虑。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    #define rep(i, s, t) for(int i = (s); i <= (t); i++)
    #define dwn(i, s, t) for(int i = (s); i >= (t); i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 11111
    #define maxm 46010
    #define oo 2147483647
    #define ool (1ll << 60)
    #define LL long long
    
    struct Edge {
    	int from, to, flow, cost;
    	Edge() {}
    	Edge(int _1, int _2, int _3, int _4): from(_1), to(_2), flow(_3), cost(_4) {}
    };
    struct ZKW {
    	int n, m, s, t, head[maxn], nxt[maxm];
    	LL cost, ans;
    	Edge es[maxm];
    	LL d[maxn];
    	int Q[maxn*10], hd, tl;
    	bool inq[maxn];
    	bool vis[maxn];
    	
    	void init() {
    		m = 0; memset(head, -1, sizeof(head));
    		return ;
    	}
    	void setn(int _) {
    		n = _;
    		return ;
    	}
    	
    	void AddEdge(int a, int b, int c, int d) {
    		es[m] = Edge(a, b, c, d); nxt[m] = head[a]; head[a] = m++;
    		es[m] = Edge(b, a, 0, -d); nxt[m] = head[b]; head[b] = m++;
    		return ;
    	}
    	
    	bool BFS() {
    		rep(i, 1, n) d[i] = ool;
    		d[t] = 0;
    		hd = tl = 0; Q[++tl] = t; inq[t] = 1;
    		while(hd < tl) {
    			int u = Q[++hd]; inq[u] = 0;
    			for(int i = head[u]; i != -1; i = nxt[i]) {
    				Edge& e = es[i^1];
    				if(d[e.from] > d[u] + e.cost && e.flow) {
    					d[e.from] = d[u] + e.cost;
    					if(!inq[e.from]) {
    						inq[e.from] = 1;
    						Q[++tl] = e.from;
    					}
    				}
    			}
    		}
    		if(d[s] == ool) return 0;
    		cost = d[s];
    		return 1;
    	}
    	
    	int DFS(int u, int a) {
    		if(u == t || !a) return ans += cost * a, a;
    		if(vis[u]) return 0;
    		vis[u] = 1;
    		int flow = 0, f;
    		for(int i = head[u]; i != -1; i = nxt[i]) {
    			Edge& e = es[i];
    			if(d[e.to] == d[u] - e.cost && (f = DFS(e.to, min(a, e.flow)))) {
    				flow += f; a -= f;
    				e.flow -= f; es[i^1].flow += f;
    				if(!a) return flow;
    			}
    		}
    		return flow;
    	}
    	
    	int MaxFlow(int _s, int _t) {
    		s = _s; t = _t;
    		int flow = 0, f;
    		while(BFS())
    			do {
    				memset(vis, 0, sizeof(vis));
    				f = DFS(s, oo);
    				flow += f;
    			} while(f);
    		return flow;
    	}
    } sol;
    
    #define maxdays 1010
    #define maxvol 10010
    
    int CntP;
    struct Point {
    	int id;
    	Point(): id(0) {}
    	int p() { return id ? id : id = ++CntP; }
    } Days[maxdays], Vol[maxvol], S, T;
    
    int main() {
    	int days = read(), vol = read();
    	sol.init();
    	rep(i, 1, days) {
    		int lim = read();
    		sol.AddEdge(S.p(), Days[i+1].p(), lim, 0);
    		sol.AddEdge(Days[i].p(), T.p(), lim, 0);
    		sol.AddEdge(Days[i].p(), Days[i+1].p(), oo - lim, 0);
    	}
    	rep(i, 1, vol) {
    		int s = read(), t = read(), c = read();
    		sol.AddEdge(Vol[i].p(), Days[s].p(), oo, c);
    		sol.AddEdge(Days[t+1].p(), Vol[i].p(), oo, 0);
    	}
    	sol.setn(CntP);
    	
    	sol.MaxFlow(S.p(), T.p());
    	printf("%lld
    ", sol.ans);
    	
    	return 0;
    }
    
  • 相关阅读:
    <置顶>Eclipse和myeclipse常用快捷键-操作-设置
    Eclipse : Loading descriptor for ...错误解决
    ORA-00937: 不是单组分组函数
    An error has occurred,See error log for more details 错误解决办法
    [Error Code: 942, SQL State: 42000] ORA-00942: 表或视图不存在
    ORA-00001: 违反唯一约束条件
    eclipse 出现user operation is waiting
    [空格][空白][特殊]字符/文字
    powerdesigner16.5安装教程及破解步骤
    mybatis遇到日期类型数据时String到date的转化
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/5474420.html
Copyright © 2011-2022 走看看