[NOI2008] volunteer recruitment (cost stream)

Posted by apaxson on Mon, 24 Jan 2022 14:18:04 +0100

[NOI2008] volunteer recruitment (cost stream)

Title Description

After his successful bid for the Olympic Games, Bubu finally became the director of the human resources department of the company subordinate to the Olympic Organizing Committee. As soon as Bubu took office, he encountered a problem: recruit a group of short-term volunteers for the upcoming new Olympic project. It is estimated that the project needs n n n days to complete, of which i i i days at least a i a_i ai , personal. Bubu learned through understanding that there are m m Category m volunteers can be recruited. Among them i i Class i can be selected from s i s_i si # working day to day t i t_i ti # days, the recruitment fee is per person c i c_i ci yuan. In order to do his job well, Bubu hopes to recruit enough volunteers at as little cost as possible, but this is not his specialty! So Bubu finds you and hopes you can help him design an optimal recruitment plan.

Input / output format

Input format

The first line contains two integers n , m n,m n. M indicates the number of days to complete the project and the types of volunteers that can be recruited. The next line contains n n n non negative integers representing the minimum number of volunteers required per day. Next m m Each row in row m contains three integers s i , t i , c i s_i, t_i, c_i si, ti, ci, have the meanings set forth above. For convenience, we can think that the number of volunteers in each category is unlimited

Output format

Contains only an integer that represents the total cost of the optimal solution you have designed.

Sample input and output

Input samples #1

3 3
2 3 4
1 2 2
2 3 5
3 3 2

Output samples #1

14

explain

1 ≤ n ≤ 1000 1\leq n\leq 1000 1≤n≤1000, 1 ≤ m ≤ 10000 1\leq m\leq 10000 1 ≤ m ≤ 10000, other data involved in the topic shall not exceed 2 31 − 1 2^{31}-1 231−1.

thinking

For this question, we can make the following assumptions:
The number of volunteers working on day i is P i P_i Pi, the number of volunteers of type i is X i X_i Xi, the minimum number of volunteers required on day i is a i a_i ai​
Then we can list the following equations without losing generality:
P 1 = X 1 + X 2 ≥ a 1 P 2 = X 1 + X 3 ≥ a 2 P 3 = X 3 ≥ a 3 \begin{aligned} P_1 &= X_1 + X_2 &\geq a_1\\ P_2 &=X_1 + X_3& \geq a_2\\ P_3 &= X_3 &\geq a_3 \end{aligned} P1​P2​P3​​=X1​+X2​=X1​+X3​=X3​​≥a1​≥a2​≥a3​​
Next, set a set of nonnegative integers Y i Y_i Yi, and add two special equations
P 0 = 0 P 1 = X 1 + X 2 − Y 1 = a 1 P 2 = X 1 + X 3 − Y 2 = a 2 P 3 = X 3 − Y 3 = a 3 P 4 = 0 \begin{aligned} P_0 &= 0\\ P_1 &= X_1 + X_2 -Y_1 &= a_1\\ P_2 &=X_1 + X_3 -Y_2 &= a_2\\ P_3 &= X_3 - Y_3 &=a_3\\ P_4 &= 0 \end{aligned} P0​P1​P2​P3​P4​​=0=X1​+X2​−Y1​=X1​+X3​−Y2​=X3​−Y3​=0​=a1​=a2​=a3​​
We make a difference between each equation and the previous equation
P 1 − P 0 = X 1 + X 2 − Y 1 = a 1 P 2 − P 1 = X 3 − X 2 + Y 1 − Y 2 = a 2 − a 1 P 3 − P 2 = − X 1 + Y 2 − Y 3 = a 3 − a 2 P 4 − P 3 = − X 3 + Y 3 = − a 3 \begin{aligned} P_1- P0 &= X_1 + X_2 -Y_1 &= a_1\\ P_2-P_1 &= X_3-X_2 +Y_1-Y_2 &= a_2 - a_1\\ P_3 -P_2&= -X_1+Y_2 - Y_3 &= a_3-a_2\\ P_4 -P_3&= -X_3 +Y_3 &=-a_3 \end{aligned} P1​−P0P2​−P1​P3​−P2​P4​−P3​​=X1​+X2​−Y1​=X3​−X2​+Y1​−Y2​=−X1​+Y2​−Y3​=−X3​+Y3​​=a1​=a2​−a1​=a3​−a2​=−a3​​
We move all variables and constants to the same side
− X 1 − X 2 + Y 1 + a 1 = 0 − X 3 + X 2 − Y 1 + Y 2 + a 2 − a 1 = 0 X 1 − Y 2 + Y 3 + a 3 − a 2 = 0 − X 3 + Y 3 − a 3 = 0 \begin{aligned} -X_1 - X_2 +Y_1 + a_1 &= 0 \\ -X_3+X_2 -Y_1+Y_2 +a_2 - a_1&=0 \\ X_1-Y_2 + Y_3 +a_3-a_2 &= 0\\ -X_3 +Y_3 -a_3 &= 0 \end{aligned} −X1​−X2​+Y1​+a1​−X3​+X2​−Y1​+Y2​+a2​−a1​X1​−Y2​+Y3​+a3​−a2​−X3​+Y3​−a3​​=0=0=0=0​
If we compare the sign in each formula with inflow and outflow, then this is obviously a network flow. According to the network flow diagram, the variable flow is INF, and the constant flows in from the source point or out from the sink point. Since we also require that our costs be minimal, the X variable has value.
So far, the answer can be obtained by using MCMF.

code

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int N = 1e3+5 , M = 4e4+5 , INF = 0x3f3f3f3f;
int tot,head[N],nxt[M],to[M],w[M],c[M],dis[N],cur[N];
bool inq[N],vis[N];
int n,m,s,t,P[N];

void add_edge(int a,int b,int x,int y)
{
    nxt[++tot] = head[a] , head[a] = tot , to[tot] = b , w[tot] = x ,c[tot] = y;
    nxt[++tot] = head[b] , head[b] = tot , to[tot] = a , w[tot] = 0 ,c[tot] = -y;
}

bool spfa()
{
    memset(dis,0x3f,sizeof(dis));
    memcpy(cur,head,sizeof(head));
    memset(inq,0,sizeof(inq));
    memset(vis,0,sizeof(vis));
    queue<int> q;
    dis[s] = 0;
    inq[s] = 1;
    q.push(s);
    while(q.size())
    {
        int x = q.front();
        q.pop();
        inq[x] = 0;
        for(int i = head[x] ; ~i ; i = nxt[i])
        {
            int y = to[i] , vol = w[i] , cost = c[i];
            if( vol > 0 && dis[y] > dis[x] + cost)
            {
                dis[y] = dis[x] + cost;
                if(!inq[y])
                {
                    q.push(y);
                    inq[y] = 1;
                }
            }
        }
    }
    return dis[t] != INF;
}

int dfs(int x = s ,int flow = INF )
{
    if(x == t)
        return flow;
    vis[x] = 1;
    int rest = flow;
    for(int & i = cur[x] ; ~i && rest ; i = nxt[i])
    {
        int y = to[i] , vol = w[i] , cost = c[i];
        if(vol > 0 && !vis[y] && dis[y] == dis[x] + cost)
        {
            int maxflow = dfs(y,min(rest,vol));
            rest -= maxflow;
            w[i] -= maxflow;
            w[i^1] += maxflow;
        }
    }
    return flow - rest;
}

int MCMF()
{
    int ans = 0;
    while(spfa())
    {
        ans += dfs() * dis[t];
    }
    
    return ans;
}

int main()
{
    scanf("%d%d", &n, &m);
    memset(head,-1,sizeof(head));
    tot = -1;
    s = 0 , t = n + 3;
    for(int i = 1 ; i <= n ; i ++)
    {
        scanf("%d", P+i);
    }
    for(int i = 1 ; i <= m ; i ++)
    {
        int l,r,C;
        scanf("%d%d%d",&l,&r,&C);
        add_edge(l,r+1,INF,C);
    }
    for(int i = 1 ; i <= n + 1; i ++)
    {
        if(P[i] - P[i-1] >= 0)
            add_edge(s,i,P[i]-P[i-1],0);
        else
            add_edge(i,t,P[i-1]-P[i],0);
        if(i > 1)
            add_edge(i,i-1,INF,0);
    }
    printf("%d",MCMF());
    return 0;
}

Topics: Algorithm