codeforces 913 c Party Lemonade(贪心+DP)


2018-2-5超时错误更新:
    使用宏#define min(a,b) (a)<(b)?(a):(b)时
    在min()里面直接调用递归函数,会多出一次额外调用导致程序不会停止,现已更正

A New Year party is not a New Year party without lemonade! As usual, you are expecting a lot of guests, and buying lemonade has already become a pleasant necessity.

Your favorite store sells lemonade in bottles of n different volumes at different costs. A single bottle of type i has volume 2i1 liters and costs ci roubles. The number of bottles of each type in the store can be considered infinite.

You want to buy at least L liters of lemonade. How many roubles do you have to spend?

Input

The first line contains two integers n and L (1  n   30; 1  L 109 ) — the number of types of bottles in the store and the required amount of lemonade in liters, respectively.

The second line contains n integers c1 ,  c2 ,  ... ,  cn (1  ci 109 ) — the costs of bottles of different types.
Output

Output a single integer — the smallest number of roubles you have to pay in order to but at least L liters of lemonade.

题意:有n家店铺在卖柠檬汁,在第 i 家店铺每次可以花ai元买 2i1 毫升。问最少花多少钱买够 L 毫升?

思路:把各店铺按单位毫升的价格(ai2i1)排序,最划算的那家店铺自然是第一家。当 L ÷ s[1].v 不能除尽时,余数部分的处理方法可能有

在第一家再买一杯
在不那么划算但一杯的价格便宜一点的第二家买足够的量
在第二家买一杯,还差的量在第三家买够

动态规划思想就是用来解决这类问题的撒~
值得一提的是,当出现余数的时候,购买的果汁有一部分可能是不需要的,就导致每家店铺的划算程度发生改变,当前店铺可能不再是最优,所以需要尝试一下在其他店铺能不能组合除对于余数部分最优的方案。

#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 30
#define min(a,b) (a)<(b)?(a):(b)
typedef long long ll;

//店铺类并重载<运算符
class store {
public:
    ll vol;
    ll cost;
    bool operator<(store a) {
        return (a.cost* vol > cost*a.vol);
    }
}s[maxn + 5];

ll n, l;

//动态规划处理余数部分
ll ans(ll left,ll cost,int si) {

    //以还差left毫升柠檬汁,已经花cost元的状态进入店铺si

    //先尽可能在这家店购买
    ll i = left / s[si].vol;//计算购买的杯数
    cost += i*s[si].cost;//更新花费状态
    left -= i*s[si].vol;//更新剩余量状态
    //如果没有余数部分,则方案最优,直接返回
    if (left == 0)return cost;
    //如果已经是最后一家,就算柠檬汁会超出需要的量,但此时只能在这里购买
    if (si == n)return cost + s[i].cost;
    //处理余数部分:再买一杯超出需要的量或者去下一家店,两种取最少花费的那种
    ll temp=ans(left, cost, si +1);
    return min(cost + s[si].cost, temp);
}

int main() {
    s[1].vol = 1;
    cin >> n >> l;
    cin >> s[1].cost;
    for (int i = 2; i <= n; ++i) {
        cin >>s[i].cost;
        s[i].vol = 2 * s[i-1].vol;
    }
    sort(s+1, s + n+1);

    ll tempm = 0;
    ll left = l;
    ll temp;
    cout << ans(left, tempm, 1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值