• 【Luogu P3980】[NOI2008] 志愿者招募


    志愿者招募

    链接:

    洛谷

    题目大意:

    (i) 天要 (a_i) 个人。第 (j) 种人从第 (s_j) 天干到第 (t_j) 天,要花 (c_j) 元。

    找到一种方案使得付出的钱最少。

    正文:

    这是一种线性规划类问题,最小化 (sum_{i=1}^m x_ic_i),且满足:

    [left{egin{matrix} sum_{i=1}^m [s_ileq1leq t_i]x_i &geq a_1 \ sum_{i=1}^m [s_ileq2leq t_i]x_i &geq a_2 \ vdots end{matrix} ight.]

    考虑用费用流。在用费用流解决某线性规划类的问题时,可以考虑把约束条件的每行看作一点(本题为第 (i) 天),建立 (n+1) 个点,那么假设有边 ((u,v))。则表示已解决 (v-1) 个约束条件,现在要处理第 (v) 个。

    考虑建模:

    1. (S) 连向 (1)(n+1) 连向 (T),流量是 (+infty),费用 (0)
    2. (i) 连向 (i+1),流量是 (+infty-a_i),费用 (0)
    3. (s_i) 连向 (t_i+1),流量 (+infty),费用 (c_i)

    那么最大流一定是 (+infty),否则无解。

    代码:

    const int N = 1010, M = 10010;
    const ll inf = 1e18;
    
    inline ll Read()
    {
    	ll x = 0, f = 1;
    	char c = getchar();
    	while (c != '-' && (c < '0' || c > '9')) c = getchar();
    	if (c == '-') f = -f, c = getchar();
    	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
    	return x * f;
    }
    
    int n, m, s, t;
    
    struct edge
    {
    	ll to, w, val, nxt;
    }e[(N + M) << 1];
    int head[N], tot = 1;
    
    void add(int u, int v, ll w, ll val)
    {
    	e[++tot] = (edge) {v, w, val, head[u]}, head[u] = tot;
    	e[++tot] = (edge) {u, 0, -val, head[v]}, head[v] = tot;
    }
    
    int pre[N];
    bool vis[N];
    ll dis[N], incf[N];
    queue <int> q;
    bool SPFA()
    {
    	memset (dis, 0x3f3f3f3f, sizeof dis);
    	while (!q.empty()) q.pop();
    	q.push(s);
    	vis[s] = 1; dis[s] = 0; incf[s] = inf;
    	while (!q.empty())
    	{
    		int u = q.front(); q.pop();
    		vis[u] = 0;
    		for (int i = head[u]; i; i = e[i].nxt)
    		{
    			int v = e[i].to;
    			if (dis[v] > dis[u] + e[i].val && e[i].w)
    			{
    				dis[v] = dis[u] + e[i].val;
    				pre[v] = i, incf[v] = min(incf[u], e[i].w);
    				if (!vis[v]) vis[v] = 1, q.push(v);
    			} 
    		}
    	}
    	return dis[t] < inf;
    }
    
    ll MCMF()
    {
    	ll cost = 0;
    	while (SPFA())
    	{
    		int u = t; cost += dis[t] * incf[t];
    		for (; u != s; u = e[pre[u] ^ 1].to)
    			e[pre[u]].w -= incf[t],
    			e[pre[u] ^ 1].w += incf[t];
    	}
    	return cost;
    }
    
    int main()
    {
    	n = Read(), m = Read(), s = n + 2, t = s + 1;
    	add(s, 1, inf, 0); 
    	for (int i = 1; i <= n; i++)
    	{
    		ll val = Read();
    		add(i, i + 1, inf - val, 0);
    	}
    	for (int i = 1; i <= m; i++)
    	{
    		int u = Read(), v = Read(); ll w = Read();
    		add(u, v + 1, inf, w);
    	}
    	add(n + 1, t, inf, 0);
    	printf ("%lld
    ", MCMF());
    	return 0;
    }
    
  • 相关阅读:
    题解【LOJ10094】「一本通 3.5 练习 2」消息的传递
    Codeforces Round #644 (Div. 3) 题解
    题解【洛谷P3627】[APIO2009]抢掠计划
    HDU-4416 Good Article Good sentence 后缀自动机
    HDU-6274 Master of Sequence 数学+二分
    Codeforces 666E Forensic Examination 广义后缀自动机+线段树合并+树上倍增
    HDU-5955 Guessing the Dice Roll AC自动机+高斯消元
    Codeforces 1437G Death DBMS AC自动机
    Codeforces 1037H Security sam+线段树合并
    2020ICPC·小米 网络选拔赛第一场 E-Phone Network 线段树
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/15026182.html
Copyright © 2020-2023  润新知