zoukankan      html  css  js  c++  java
  • @bzoj


    @description@

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

    Input
      第一行包含两个整数N, M,表示完成项目的天数和可以招募的志愿者的种类。 接下来的一行中包含N 个非负整数,表示每天至少需要的志愿者人数。 接下来的M 行中每行包含三个整数Si, Ti, Ci,含义如上文所述。为了方便起见,我们可以认为每类志愿者的数量都是无限多的。

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

    Sample Input
    3 3
    2 3 4
    1 2 2
    2 3 5
    3 3 2
    Sample Output
    14

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

    @solution@

    听说可以线性规划建模,但我不会。。。
    但至少可以看出来这是个比较显然的线性规划,看数据范围发现单纯形过不去,于是联想到网络流。

    考虑题设所说至少需要 Ai 个人,其实可以对应到上下界网络流中的下界。
    新增 0 号点,对于每一个 1 <= i <= n,连 i-1 -> i 这条边表示第 i 天招募的志愿者数量。则这条边下界为 Ai,上界为 inf,费用为 0。

    题目说可以用 Ci 的费用将 Si 到 Ti 这些天对应的边流量加一。。。
    考虑使用流量平衡思想,Si 到 Ti 这些天对应的边形成一条链 Si - 1 -> Si -> ... -> Ti。如果连边 Ti -> Si - 1,就可以形成环流,满足流量平衡的限制。
    所以,我们在原本的上下界网络流中连 Ti -> Si - 1,下界为 0,上界为 inf,费用为 Ci。

    在这个上下界流网络中跑最小可行无源汇流即可。

    @accepted code@

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int MAXN = 1000;
    const int MAXM = 10000;
    const int MAXV = 1000;
    const int MAXE = 2*MAXM + 5*MAXV + 5;
    const int INF = (1<<30);
    struct FlowGraph{
    	struct edge{
    		int to, cap, flow, cost;
    		edge *nxt, *rev;
    	}edges[MAXE + 5], *adj[MAXV + 5], *cur[MAXV + 5], *ecnt;
    	FlowGraph() {ecnt = &edges[0];}
    	int s, t;
    	void addedge(int u, int v, int c, int w) {
    		edge *p = (++ecnt), *q = (++ecnt);
    		p->to = v, p->cap = c, p->flow = 0, p->cost = w;
    		p->nxt = adj[u], adj[u] = p;
    		q->to = u, q->cap = 0, q->flow = 0, q->cost = -w;
    		q->nxt = adj[v], adj[v] = q;
    		p->rev = q, q->rev = p;
    //		printf("! %d %d %d %d
    ", u, v, c, w);
    	}
    	int f[MAXV + 5], hp[MAXV + 5];
    	void update(int x, int k) {
    		f[x] = k;
    		while( x ) {
    			hp[x] = x;
    			if( (x<<1) <= t && f[hp[x<<1]] < f[hp[x]] )
    				hp[x] = hp[x<<1];
    			if( (x<<1|1) <= t && f[hp[x<<1|1]] < f[hp[x]] )
    				hp[x] = hp[x<<1|1];
    			x >>= 1;
    		}
    	}
    	int d[MAXV + 5], h[MAXV + 5];
    	bool relabel() {
    		for(int i=1;i<=t;i++)
    			h[i] += d[i], d[i] = f[i] = INF, hp[i] = i, cur[i] = adj[i];
    		update(s, d[s] = 0);
    		while( f[hp[1]] != INF ) {
    			int x = hp[1]; update(x, INF);
    			for(edge *p=adj[x];p;p=p->nxt) {
    				int w = p->cost + h[x] - h[p->to];
    				if( p->cap > p->flow && d[x] + w < d[p->to] )
    					update(p->to, d[p->to] = d[x] + w);
    			}
    		}
    		return !(d[t] == INF);
    	}
    	bool vis[MAXV + 5];
    	int aug(int x, int tot) {
    		if( x == t ) return tot;
    		int sum = 0; vis[x] = true;
    		for(edge *&p=cur[x];p;p=p->nxt) {
    			int w = p->cost + h[x] - h[p->to];
    			if( !vis[p->to] && p->cap > p->flow && d[x] + w == d[p->to] ) {
    				int del = aug(p->to, min(tot - sum, p->cap - p->flow));
    				p->flow += del, p->rev->flow -= del, sum += del;
    				if( sum == tot ) break;
    			}
    		}
    		vis[x] = false;
    		return sum;
    	}
    	int min_cost_max_flow(int _s, int _t) {
    		s = _s, t = _t; int cost = 0;
    		while( relabel() )
    			cost += (h[t] + d[t])*aug(s, INF);
    		return cost;
    	}
    }G;
    int A[MAXN + 5];
    int N, M, s, t;
    int main() {
    	scanf("%d%d", &N, &M), s = N + 2, t = N + 3;
    	for(int i=1;i<=N;i++)
    		scanf("%d", &A[i]);
    	for(int i=0;i<=N;i++) {
    		if( A[i] < A[i + 1] )
    			G.addedge(i + 1, t, A[i + 1] - A[i], 0);
    		else if( A[i] > A[i + 1] )
    			G.addedge(s, i + 1, A[i] - A[i + 1], 0);
    	}
    	for(int i=0;i<N;i++)
    		G.addedge(i + 1, i + 2, INF, 0);
    	for(int i=1;i<=M;i++) {
    		int S, T, C; scanf("%d%d%d", &S, &T, &C);
    		G.addedge(T + 1, S, INF, C);
    	}
    	printf("%d
    ", G.min_cost_max_flow(s, t));
    }
    

    @details@

    其实最后建出来的图和线性规划建模方法是一致的。

    另外,代码中个人的实现习惯原因,所有点的编号都往后移动了一位(即原本 0 号点变 1 号点,以此类推)。

    以及我也不知道为什么这个数据范围看起来就是要开longlong但我用int过了,写完交发现A过后才反应过来

  • 相关阅读:
    牛牛与LCM(最小公约数)
    小明的挖矿之旅_牛客网(思维题)
    2019/4/20周赛 F题 CodeForces
    哥德巴赫猜想_2019/7/11_牛客网
    智障操作-wireless AC 9462
    codeforces762A
    2019中山大学程序设计竞赛(重现赛)斐波那契/
    Java自学笔记(10):【面向对象 】 类和对象、构造方法、this关键字
    Java自学笔记(9):方法
    Java自学笔记(8):多维数组
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/11416749.html
Copyright © 2011-2022 走看看