EOJ:Buying Feed【单调队列优化】

——problem:从0出发到E,有一个容量为K的背包,途中有N个商店出售物品,物品价格不同且搬运物品的费用为k*k*D,k为当前背包的重量。求到终点背包容量恰为K的最小费用。

——solution:树形DP

——url:http://202.120.106.94/onlinejudge/problemshow.php?pro_id=440

_______________________________________________________________

明显的DP

转移方程DP[I][J]=MIN{DP[I-1][K]+K*K*(D[I]-D[I-1])+(J-K)*C[I]}       J-F[I]<=K<=J

根据题目数据给的范围,500(I的范围)*10000(J的范围)*500(K的范围) 肯定要超时。  

于是用单调队列优化

关于单调队列:

队头的元素肯定是最小的(最大的)

取元素操作:

    从队头取出元素,直到该元素在要求的范围内(本题即为J-F[I]<=K<=J)

插入元素操作:

    若队尾元素比插入的元素要大,则删除。直到比待插入的元素小为止,然后再插入元素。

另外通过本题明确了队列的用法

头指针指向第一个元素,尾指针指向最后一个元素的后一位。若头尾指针相等则队列为空。

#include<stdio.h>
#include<memory.h>
#include<stdlib.h>
#include<queue>
using namespace std;
#define oo 1LL<<60
#define N 505
#define M 10005
struct node1
{
    long long x, f, c;
} food[N];
struct node2
{
    long long value, id;
} q[M];
long long dp[N][M];
long long head, tail, k, e, n, i, j, l, ans, tmp;
int cmp(const void *a, const void *b)
{
    return (*(node1 *) a).x - (*(node1 *) b).x;
}
long long min(long long a, long long b)
{
    return a < b ? a : b;
}
long long max(long long a, long long b)
{
    return a > b ? a : b;
}
void init()
{
    scanf("%lld%lld%lld", &k, &e, &n);
    for (i = 1; i <= n; i++)
        scanf("%lld%lld%lld", &food[i].x, &food[i].f, &food[i].c);
    food[0].x = 0;
    qsort(food, n + 1, sizeof(food[0]), cmp);
}
long long work()
{
    long long up_bound, MIN;
    for (i = 0; i <= n; i++)
        for (j = 0; j <= k; j++)
            dp[i][j] = oo;
    up_bound = 0;
    dp[0][0] = 0;
    for (i = 1; i <= n; i++)
    {
        up_bound = min(up_bound + food[i].f, k);
        head = tail = 0;
        for (j = 0; j <= up_bound; j++)
        {
            while (head < tail && q[head].id < max(0, j - food[i].f))     //单调队列优化
                head++;
            tmp = dp[i - 1][j] + j * j * (food[i].x - food[i - 1].x) - j
                    * food[i].c;
            while (head < tail && q[tail - 1].value > tmp)
                tail--;
            q[tail].value = tmp;
            q[tail++].id = j;
            MIN = q[head].value;
            dp[i][j] = MIN + j * food[i].c;
        }
    }
    return dp[n][k];
}
int main()
{
    init();
    ans = work();
    ans += k * k * (e - food[n].x);
    printf("%lld\n", ans);
    return 0;
}

  

posted on 2011-07-24 21:48  风也轻云也淡  阅读(196)  评论(0编辑  收藏  举报