zoukankan      html  css  js  c++  java
  • 【luogu P3980】Volunteer / 志愿者招募(网络流)

    Volunteer / 志愿者招募

    题目链接:luogu P3980

    题目大意

    有 n 天,每天需要 ai 个人。
    有几种人,每种人有招募费用,它能干活干一个区间的时间段。
    然后每种人可以选无限个,问你要的最小费用。

    思路

    你首先看到范围想到网络流。
    结果你发现你招募一个人,却要干几天,你一个流量变不了多个,似乎很难搞。

    那你考虑换一个建模的方法,变成你干 (isim j) 天变成 (i) 连到 (j+1) 表示你第 (i) 天的人直接干活到了 (j+1),流量是无限(可以选无限个人),费用就是选人的费用。(如果 (j=n) 直接连到汇点)
    那你会想,你人可以不用干那么多天,那你就可以 (j) 连向 (j-1),费用 (0),流量无限,表示你少搞一天。
    但它每天人数限制会变啊,那你就根据每天的变化做出调整:
    如果多了 (x),就源点连向它,流量是 (x),费用 (0)
    如果少了 (x),就它连向汇点,流量是 (x),费用 (0)
    (因为是最大流,所以他一定会流,就可以)

    (当然这里你可以全部流源点连向它,那然后负流量就加一个很大的值来搞)

    然后跑最小费用最大流就可以了。

    代码

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream> 
    #define ll long long
    #define INF 0x3f3f3f3f3f3f3f3f
    
    using namespace std;
    
    struct node {
    	ll x;
    	int to, nxt, op;
    	ll val;
    }e[500001];
    int n, m, S, T;
    int le[2001], KK, x, y;
    int deg[2001];
    ll dis[2001], a[1001], ans, z;
    bool in[2001];
    queue <int> q;
    
    void add(int x, int y, ll z, ll val) {
    	e[++KK] = (node){z, y, le[x], KK + 1, val}; le[x] = KK;
    	e[++KK] = (node){0, x, le[y], KK - 1, -val}; le[y] = KK;
    }
    
    bool SPFA() {
    	memset(dis, 0x7f, sizeof(dis));
    	memset(deg, 0, sizeof(deg));
    	while (!q.empty()) q.pop();
    	dis[S] = 0;
    	in[S] = 1;
    	deg[S] = 1;
    	q.push(S);
    	while (!q.empty()) {
    		int now = q.front();
    		q.pop();
    		
    		for (int i = le[now]; i; i = e[i].nxt)
    			if (dis[e[i].to] > dis[now] + e[i].val && e[i].x) {
    				dis[e[i].to] = dis[now] + e[i].val;
    				deg[e[i].to] = deg[now] + 1; 
    				if (!in[e[i].to]) {
    					in[e[i].to] = 1;
    					q.push(e[i].to);
    				}
    			}
    		
    		in[now] = 0;
    	}
    	
    	return dis[T] != dis[0];
    }
    
    ll dfs(int now, ll sum) {
    	if (now == T) return sum;
    	ll go = 0;
    	in[now] = 1;
    	for (int i = le[now]; i; i = e[i].nxt)
    		if (e[i].x && dis[e[i].to] == dis[now] + e[i].val && deg[e[i].to] == deg[now] + 1 && !in[e[i].to]) {
    			ll this_go = dfs(e[i].to, min(sum - go, e[i].x));
    			if (this_go) {
    				e[i].x -= this_go;
    				e[e[i].op].x += this_go;
    				go += this_go;
    				if (go == sum) {
    					in[now] = 0;
    					return go;
    				}
    			}
    		}
    	in[now] = 0;
    	return go;
    }
    
    void dinic() {
    	while (SPFA())
    		ans += dis[T] * dfs(S, INF);
    }
    
    int main() {
    	scanf("%d %d", &n, &m);
    	for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    	
    	S = n + 1;
    	T = n + 2;
    	for (int i = 2; i <= n; i++) {
    		add(i, i - 1, INF, 0);//可以退回去(不用干那么多天)
    	}
    	for (int i = 1; i <= n; i++) {
    		if (a[i] - a[i - 1] > 0) add(S, i, a[i] - a[i - 1], 0);//比之前多人,要多流
    			else add(i, T, a[i - 1] - a[i], 0);//比之前少人,要流一些到终点
    	}
    	
    	for (int i = 1; i <= m; i++) {
    		scanf("%d %d %lld", &x, &y, &z);
    		if (y == n)	add(x, T, INF, z);//流完就代表走完
    			else add(x, y + 1, INF, z);//流过这个区间
    	}
    	
    	dinic();
    	
    	printf("%lld", ans);
    	
    	return 0;
    }
    
  • 相关阅读:
    VScode 修改中文字体
    missing KW_END at ')' near '<EOF>'
    SQL inner join, join, left join, right join, full outer join
    SQL字符替换函数translater, replace
    SQL COOKBOOK SQL经典实例代码 笔记第一章代码
    sqlcook sql经典实例 emp dept 创建语句
    dateutil 2.5.0 is the minimum required version python
    安装postgresql后找不到服务 postgresql service
    Postgres psql: 致命错误: 角色 "postgres" 不存在
    【西北师大-2108Java】第十六次作业成绩汇总
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/luogu_P3980.html
Copyright © 2011-2022 走看看