poj1821 Fence(dp,单调队列优化)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhanghaoxian1/article/details/81974006

Fence

Description
A team of k (1 <= K <= 100) workers should paint a fence which contains N (1 <= N <= 16 000) planks numbered from 1 to N from left to right. Each worker i (1 <= i <= K) should sit in front of the plank Si and he may paint only a compact interval (this means that the planks from the interval should be consecutive). This interval should contain the Si plank. Also a worker should not paint more than Li planks and for each painted plank he should receive Pi $ (1 <= Pi <= 10 000). A plank should be painted by no more than one worker. All the numbers Si should be distinct.
Being the team’s leader you want to determine for each worker the interval that he should paint, knowing that the total income should be maximal. The total income represents the sum of the workers personal income.
Write a program that determines the total maximal income obtained by the K workers.

Input
The input contains:
Input
N K
L1 P1 S1
L2 P2 S2

LK PK SK
Semnification
N -the number of the planks; K ? the number of the workers
Li -the maximal number of planks that can be painted by worker i
Pi -the sum received by worker i for a painted plank
Si -the plank in front of which sits the worker i

Output
The output contains a single integer, the total maximal income.

Sample Input
8 4
3 2 2
3 2 3
3 3 5
1 1 7

Sample Output
17

Hint
Explanation of the sample:
the worker 1 paints the interval [1, 2];
the worker 2 paints the interval [3, 4];
the worker 3 paints the interval [5, 7];
the worker 4 does not paint any plank

题意:M个工匠刷N块木板,每块木板至多刷一次,第i个工匠只能粉刷包含木板Si,长度不超过Li的连续一段,每粉刷一块木板可获得Pi的报酬,求所有工匠的最大报酬。

分析:将工匠按Si排序,设f[i][j]表示前i个工匠粉刷到第j块木板时的最大报酬,显然,对于第i个工匠,他可以不刷第j块木板,也可以什么都不刷,即f[i][j]=max(f[i-1][j],f[i][j-1]),如果他选择粉刷第k+1块到第j块,f[i][j]=max{f[i-1][k]+Pi*(j-k)}j-Li<=k<=Si-1,j>=Si。考虑优化。由于Pi*j为定值,将它提出来,状态转移方程变为f[i][j]=Pi*j+max{f[i-1][k]-P[i]*k},不难发现,f[i-1][k]-P[i]*k可以用单调队列维护。

代码

#include <cstdio>
#include <algorithm>
#include <deque>
#define N 20000
using namespace std;

struct arr
{
    int s,l,p;
}a[200];
int f[200][N],n,m;
deque<int> q;

int cmp(arr x, arr y){return x.s <  y.s;}

int count(int i, int k){return f[i - 1][k] - a[i].p * k;}

int fmax(int x, int y){return x>y?x:y;}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++)
        scanf("%d%d%d", &a[i].l, &a[i].p, &a[i].s);
    sort(a + 1, a + m + 1, cmp);
    for (int i = 1; i <= m; i++)
    {
        while (!q.empty()) q.pop_front();
        for (int j = max(0, a[i].s - a[i].l); j < a[i].s; j++)
        {
            while (!q.empty() && count(i, j) >= count(i, q.back())) q.pop_back();
            q.push_back(j);
        }
        for (int j = 1; j <= n; j++)
        {
            f[i][j] = fmax(f[i - 1][j], f[i][j - 1]);
            if (j >= a[i].s && j <= a[i].s + a[i].l - 1)
            {
                while (!q.empty() && q.front() < j - a[i].l) q.pop_front();
                if (!q.empty()) f[i][j] = fmax(f[i][j], count(i, q.front()) + a[i].p * j);
            }
        }
    }
    printf("%d", f[m][n]);
}

猜你喜欢

转载自blog.csdn.net/zhanghaoxian1/article/details/81974006