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;
    }
    
  • 相关阅读:
    EXTJS 4.2 资料 控件之checkboxgroup的用法(静态数据)
    EXTJS 4.2 资料 控件之Window窗体相关属性的用法
    EXTJS 4.2 资料 控件之textfield文本框加事件的用法
    Entity Framework 学习笔记(一)之数据模型 数据库
    EXTJS 4.2 资料 控件之checkboxgroup的用法(动态数据)
    EXTJS 4.2 资料 控件之Grid 列鼠标悬停提示
    Entity Framework 学习笔记(二)之数据模型 Model 使用过程
    EXTJS 4.2 资料 控件之radiogroup 的用法
    EXTJS API
    vue移动端弹框组件,vue-layer-mobile
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/5474420.html
Copyright © 2011-2022 走看看