zoukankan      html  css  js  c++  java
  • [NOI2008] 志愿者招募 洛谷P3980

    链接

    这是一个看上去很贪心的问题,但是很显然不能够直接贪心。

    我们面对这一类问题一般采用 (dp) 或者网络流来进行分析。

    这里限制很多,状态复杂,因此不适合 dp ,我们不妨采用网络流来描述这样一个问题。

    我们发现,每一天都需要至少 (a_i) 个志愿者,而每种志愿者都恰好会在一段连续的日子进行工作,我们不妨将每一天拆成两个点用上下界流量来限制每一天的最少志愿者数量。

    同时,我们的一种志愿者恰好会在一段区间内工作,我们不妨使用差分的思想进行限制,让这种志愿者从 (s) 进入,(t) 回来,满足流量守恒,同时在进入的时候需要计算费用。

    最后我们只需要跑一遍无源汇最小费用可行流即可。

    代码:

    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    template <typename T>
    void read(T &x) {
    	T f=1;x=0;char s=getchar();
    	while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
    	while(s>='0'&&s<='9') {x=(x<<3)+(x<<1)+(s^'0');s=getchar();}
    	x *= f; 
    }
    
    const int MAXN = 1e6 + 5;
    const int MAXM = 1e6 + 5;
    const int inf = 1e9;
    
    int head[MAXN] , to[MAXM << 1] , nxt[MAXM << 1] , cnt = 1;
    int edge[MAXM << 1] , val[MAXM << 1];
    void add(int u , int v , int c , int w) {
    	nxt[++cnt] = head[u];head[u] = cnt;to[cnt] = v;edge[cnt] = c;val[cnt] = w;
    	nxt[++cnt] = head[v];head[v] = cnt;to[cnt] = u;edge[cnt] = 0;val[cnt] = -w;
    }
    
    int s , t , num , vis[MAXN] , cur[MAXN];
    int dis[MAXN]; 
    
    int MinCost , MaxFlow;
    bool bfs() {
    	for (int i = 1; i <= num; ++i) vis[i] = 0 , dis[i] = inf , cur[i] = head[i];
    	dis[s] = 0;
    	queue <int> q;q.push(s);
    	int flag = 0;
    	while(!q.empty()) {
    		int x = q.front();
    		q.pop();
    		vis[x] = 0;
    		for (int i = head[x]; i; i = nxt[i]) {
    			if(!edge[i]) continue;
    			int v = to[i];
    			if(dis[v] > dis[x] + val[i]) {
    				dis[v] = dis[x] + val[i];
    				if(v == t) {
    					flag = 1;
    					continue;
    				}
    				if(!vis[v]) q.push(v) , vis[v] = 1;
    			}
    		}
    	}
    	return flag;
    }
    
    int Dinic(int x , int flow) {
    	if(x == t) {
    		MaxFlow += flow;
    		MinCost += flow * dis[t];
    		return flow;
    	}
    	vis[x] = 1;
    	int rest = flow;
    	for (int i = cur[x]; i && rest; i = nxt[i]) {
    		cur[x] = i;
    		if(!edge[i]) continue;
    		int v = to[i];
    		if(!vis[v] && dis[v] == dis[x] + val[i]) {
    			int k = Dinic(v , min(rest , edge[i]));
    			if(!k) dis[v] = -inf;
    			rest -= k;
    			edge[i] -= k;
    			edge[i ^ 1] += k;
    		}
    	}
    	return flow - rest;
    }
    
    void MVMC() {
    	MinCost = MaxFlow = 0;
    	while(bfs()) Dinic(s , inf);
    }
    
    int n , m;
    
    int main() {
    	read(n),read(m);
    	num = n * 2 + m + 2;
    	s = n * 2 + m + 1 , t = n * 2 + m + 2;
    	for (int i = 1; i <= n; ++i) {
    		int x;
    		read(x);
    		add(i , t , x , 0);
    		add(s , i + n , x , 0);
    		add(i , i + n , inf - x , 0);
    		if(i != n) add(i + n , i + 1 , inf , 0);
    	}
    	for (int i = 1; i <= m; ++i) {
    		int st , ti , c;
    		read(st),read(ti),read(c);
    		add(n * 2 + i , st , inf , c);
    		add(ti + n , n * 2 + i , inf , 0);
    	}
    	MVMC();
    	printf("%d
    " , MinCost);
    	return 0;
    }
    
  • 相关阅读:
    HiDPI的社区Wiki与部分解决方案
    Linux 桌面玩家指南:在 Ubuntu 中使用 deepin-wine,解决一些依赖 Windows 的痛点问题
    如何安装 Whisker Menu菜单
    为什么用 embed 方式插入的 Flash 元素总能把其它元素盖住?修改 z-index 属性也没用。
    Python 所谓的艺术操作
    Python 画矩形
    Python pygame中的颜色
    Python 创建一个Pycharm窗口
    Python画一个圆
    汉诺塔
  • 原文地址:https://www.cnblogs.com/Reanap/p/14246971.html
Copyright © 2011-2022 走看看