POJ 2393 Yogurt factory

题目连接:http://poj.org/problem?id=2393


题目大意:

        酸奶工厂需要生产酸奶,共N周。同时,酸奶每周单位重量的价格Price不一样,且每周的需求量needs也不同,但是可以存储酸奶(一周生产多周的酸奶)且不考虑腐败的情况,存储酸奶的价格是每周每单位重量酸奶需花费S,即本周生产的酸奶多于本周的需求,则需要花钱存储起来。问:最低成本是多少?


题目分析:

        题目有这么几点需要提到:

        1. 生产能力无上限

        2. 存储酸奶的能力无上限

        3. 每周的酸奶需求都必须满足,即第i周需要x单位的酸奶,那么在第1到i周的时间内必须生产出x单位的酸奶。

      

        解决问题的核心是贪心的思路。如何贪心?出发点应该是第i周的酸奶应该在第1到i周的哪一周生产。这一点很重要,因为不同的选择决定了第i周酸奶的单位价格(该价格越小,第i周的成本越低)。而且从题目可以看出,N总共生产的酸奶应该等于N周的总需求,所以有如下公式:

                                  成本= need_1*lowprice_1 + need_2*lowprice_2 + ...........+ need_N*lowprice_N     (1)

公式里的lowprice_i代表为满足该周需求酸奶的最低生产价格,它由直接生产价格(Price)和保存价格(S)决定,公式如下:

                                    lowprice_i = min(lowprice_1, lowprice_2, ........., lowprice_i)                               (2)

其中,lowprice_i显然就是第i周的直接生产价格price_i(不要保存哈),但是前面i-1周的价格需要知道。

这里没必要每次都重复计算,那样的话算法的时间复杂度等于O(N^2)。其实,公式(2)可以简化为下式:

                                    lowprice_i = min(lowprice_i-1 + S,  lowprice_i)                                                      (3)

其中,第i-1周的最低价格加保存S的原因是多出来一周(第i周),那么当然需要保存。


       基于上面的贪心方法,时间复杂度等于O(N),C++代码如下:

       注意题目的数据范围,N周的最低成本应该用long long类型表示,对应的printf输出格式选择%lld

#include<stdio.h>
#include<algorithm>

using namespace std;

const int N_MAX = 10000;
int price[N_MAX], needs[N_MAX];
int s, N;
long long res;

void init(){
	res = 0;
	scanf("%d%d", &N, &s);
	
	for(int i = 0; i < N ; i++){
		scanf("%d%d", &price[i], &needs[i]);
	}
	
	return ;
}

void solve(){
	int lowprice = price[0];
	res += lowprice*needs[0];
	
	for(int i = 1; i < N; i++){
		lowprice = min( lowprice+s, price[i]);
		res += lowprice*needs[i];
	}

	return ;
}

int main()
{
	init();
	solve();
	printf("%lld\n", res);
    return 0;
}


感悟:

       虽然题目很水,但也是理解之后觉得水。不会之前都说,会了就不难。总之,出发点很重要,如果该题从一周应该生产未来哪些周的酸奶出发,那么问题将变得很难理解和复杂(一开始是这么想的疑问)。虽然开始绕弯,但是在弯路里发现了一些规律,对走回正道有帮助。所以,不怕走弯路,只要边走边思考,一定能回到正轨。殊途同归哈!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值