dp专题-UVA - 11400-贪心+dp

题目链接:http://fastvj.rainng.com/contest/306591#problem/F
题目大意:在这里插入图片描述

思路:我们先把所有的灯泡按电压排(升)序。

结论一:
结论1:每种灯泡要么不换,要么全换。

如果单拿两种灯泡,我们什么情况换?
(1) 灯泡2的灯泡价格比灯泡1低。
(2) 灯泡2的价格比灯泡1的价格高,但是把灯泡1全部换成灯泡2,
	可以减少灯泡的电源钱,比换灯泡的价格花费高。那么就是(L[i])*(c[j]-c[i])< K[i]

结论2:现我们将输入按照电压等级从小到大排序后,j < i,如果 j 要换成 i,
	  则从 j 到 i-1 都要换成 i。因为j换i那么减少的费用为(L[i])*(c[i]-c[j]) + K[i]
	  
	  如果 j 要换成 i,没有换成j到i之间的灯泡,那么说明c[j]是i到j中最小的。
	  那么j-i之间灯泡都满足(L[i])*(c[i]-c[j]) + K[i]>0说明他们换成i都可以使费用减少。

因为i-n的灯泡电压比i大,他们不能换成i,在这个区间里面应该重复这个过程。

//大佬思路:
如果结论2成立,那么意味着这个升序列中有几个“断层”,它们之间的弱势灯泡
要被替换为右侧大功率灯泡。
首先,第n个由于功率最大,肯定是最后一个断层。然后,此时假设断层 i 的上一个断层为 j,由于 j 和 i 之间的灯泡
都要换成 i,所以dp[i] = dp[j] + 灯泡数量*i的单价 + i的电压源价格。

该暴力的时候也得暴力一下,上一个断层 j 无法直接得出,可以遍历1~i-1看看
哪种方案最优得之。

d[i]为灯 泡1~i的最小开销
故给出状态转移方程dp[i] = min{ dp[j] + (s[i]-s[j])*C[i] + K[i] }。
因为每个灯泡要么不换,要么全换,所以s[i]是灯泡数量前缀和。

#include <bits/stdc++.h>
#define LL long long
using namespace std;

struct node
{
    int v, k, c, L;
    bool operator<(node &a)
    {
        return v<a.v;
    }
}a[1010];
LL dp[1010], s[1010];
int main()
{
    int n;
    while(scanf("%d",&n),n)
    {
        memset(s, 0, sizeof(s));
        for(int i=1;i<=n;i++)
        {
            dp[i]=(1<<31)-1;
            scanf("%d%d%d%d",&a[i].v,&a[i].k,&a[i].c,&a[i].L);
        }
        sort(a+1, a+1+n);
        for(int i=1;i<=n;i++)
        {
            s[i]=s[i-1]+a[i].L;
        }

        dp[0]=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=i;j++)
            {
                dp[i]=min(dp[j]+(s[i]-s[j])*a[i].c+a[i].k, dp[i]);
            }
        }
        printf("%lld\n",dp[n]);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值