北大OJ——Yogurt factory(贪心)

原题连接:
http://poj.org/problem?id=2393
本题题意是:有n周,每周制作+运输酸奶的价格c,需求y都有变化,另有仓库,可储存任意多的酸奶,每周每单位储存价格恒定为s,求n周最少的总成本。

本题的主要问题是:第i周的酸奶要不要之前就制作好存下来,还是直接做完卖了,就是存与不存的问题。

下面我们来探寻一下存与不存的条件。
n s
c[i], y[i] c[k],y[k]
if( (c[k]-c[i])*y[k] >= (k-i)sy[k] ) 存
else 不存
即 c[k]-c[i]~~(k-i)*s 的大小关系,大于等于存,小于不存。

不过,问题来了:
1.假设从i周开始,i+1–m-1周都在i周制作并储存,那如果在第m周同样满足可以在第i周存的条件,但会不会在i+1–m-1之间某一周k(i 2.如果i在k周不满足存的条件,那在m(m>k)周会不会重新出现在i周满足存的条件呢?
为了简化问题,我们将问题 1 ,问题 2 的答案都假设为否定。
证明问题 1:
n s
c[i] y[i] c[k] y[k] c[m] y[m]
已知:c[k]-c[i]>=(k-i)*s;
设 c[k]-c[i]=d;则d>=(k-i)*s;
比较c[m]-c[i]-(m-i)·s–c[m]-c[k]-(m-k)·s的大小(注意,不是比较c[m]-c[i]–c[m]-c[k]的大小)
亦即比较 c[m]-c[i]-(m-i)·s-(c[m]-c[k]-(m-k)·s)–0的大小

化简可得 c[k]-c[i]-(k-i)*s=d-(k-i)*s~~0;
而d>=(k-i)*s,故d-(k-i)*s>=0;
因此c[m]-c[i]-(m-i)*s>=c[m]-c[k]-(m-k)*s;
从结论可知,即使在第k周可以存,也不比在第i周存来的有利,成本一定比第i周的高,于是命题得以证明,问题 1 答案为否定。
证明问题 2:
n s
c[i] y[i] c[k] y[k] c[m] y[m]
已知:c[k]-c[i]<(k-i)*s;
设 c[k]-c[i]=d;则d<(k-i)*s;
由问题 1 的过程可得
c[m]-c[i]-(m-i)*s 因此,即使第m周的酸奶可以在第i周先制作存下来,也不比在第k周制作后存下来,成本一定比第k周高,于是问题 2 答案为否定。

总结:
1.i+1–m-1,m周的酸奶都可以在第i周制作后存下来,就不必考虑m周的酸奶可不可以在i+1–m-1制作后存下来了——只需考虑开头与结尾的关系,不需考虑中间
2.k周不可以在i周存,新的起点,即新的存储周直接定为k,不必考虑 i 对 k 周后面的影响了——新起点即为旧终点,旧起点对后面的影响不需考虑

伪代码如下:
输入 n,s
输入 c[n],y[n]
long long sum,flag=0;//flag为起点,初始为0
for(i=0;i<=n-1;i++){
if(满足存的条件)sum+=c[flag]·y[i]+s·(i-flag)·y[i]
else sum+=c[i]*y[i] flag=i;}
输出sum。

代码如下:

#include
#include
using namespace std;
long long c[10005],y[10005];
int main()
{
	int n;	//while(1){
	long long s,sum=0,flag;
	int i;
	scanf("%d %lld",&n,&s);
	flag=0;
	for(i=0;i<=n-1;i++)
    	scanf("%lld %lld",&c[i],&y[i]); 
    for(i=0;i<=n-1;i++)
	{
		if(i==0) sum+=c[i]*y[i];
		else
		{
			if(c[i]-c[flag]>=s*(i-flag))
			{
				sum+=c[flag]*y[i]+s*(i-flag)*y[i];
			}
			else
			{
				sum+=c[i]*y[i];
				flag=i;
			}
		}
	//	printf("%d %lld\n",flag,sum);
	 } 
	printf("%lld\n",sum);//}
	return 0;
}

本题的证明出来的结论要好好消化,下回遇到相似的就不用再证了。此外本题有一个特点——不可以排序。所以,至少按你目前的水平,千万别排序。

你可能感兴趣的:(贪心)