HDU - 1300 Pearls(斜率DP)

来源:互联网 发布:淘宝刷手有什么危险 编辑:程序博客网 时间:2024/05/16 15:00

题目大意:有n种珠宝,每件珠宝有必须要买的数量ai和单价pi,c种珠宝的单价递增。如果买了某种珠宝,需要额外付一次10*pi的费用,同时允许用等量的高价珠宝代替等量的的低价珠宝,问至少要花多少钱,才能达到要求

解题思路:设 dp[i]为买前i种珠宝需要花费的最小代价
得转移方程dp[i] = dp[j] + (sum[i] - sum[j] + 10) * val[i]
sum[i]指前i中珠宝的数量和
假设k > j,且k点比j点更优
则 dp[j] + (sum[i] - sum[j] + 10 ) * val[i] >= dp[k] + (sum[i] - sum[k] + 10) * val[i]

化简可得val[i] >= (dp[k] - dp[j]) / (sum[k] - sum[j])
因为价格递增,所以得到优化方程

#include <cstdio>#include <cstring>const int N = 110;int sum[N], val[N], dp[N], que[N];int n;void init() {    dp[0] = sum[0] = 0;    scanf("%d", &n);    for (int i = 1; i <= n; i++) {        scanf("%d%d", &sum[i], &val[i]);        sum[i] += sum[i - 1];    }}int getUp(int j, int k) {    return dp[j] - dp[k];}int getDown(int j, int k) {    return sum[j] - sum[k];}int getDp(int i, int j) {    return dp[j] + (sum[i] - sum[j] + 10) * val[i];}void solve(){     int head, tail;    head = tail = 0;    que[tail++] = 0;    for (int i = 1; i <= n; i++) {        while (head + 1 < tail && getUp(que[head + 1], que[head]) <= getDown(que[head + 1], que[head]) * val[i])             head++;        dp[i] = getDp(i, que[head]);        while (head + 1 < tail && getUp(i, que[tail - 1]) * getDown(que[tail - 1], que[tail - 2]) <= getUp(que[tail - 1], que[tail - 2]) * getDown(i, que[tail - 1]))            tail--;        que[tail++] = i;    }    printf("%d\n", dp[n]);}int main() {    int test;    scanf("%d", &test);    while (test--) {        init();        solve();    }    return 0;}
0 0