poj1260 pearls

题目大意:珠宝店有许多珠宝,你需要每种珠宝各买一定的数目,各种珠宝的价格是不一样的,每种珠宝买的时候都必须多付10颗该珠宝的钱,但一种珠宝可以用比它更贵的珠宝来代替,所以有时候用更贵的珠宝来充数可能更省钱。现在问你最少要多少钱?输入数据已按珠宝按价格升序排序。

分析:开始想的时候想了一个二维的方程,但是一维就够了。设f[i]表示买了第i种珠宝,前面的珠宝都已经买了或有更贵的充数,此时所花的最少的钱。

则f[i]=min(f[k]+(sum[i]-sum[k]+10)*price[i])

设y=f[k]+sum[i]*price+10*price,x=sum[k],b=prixe[i],g=f[i],则上式变为:g=y-bx

 b是递增的,所以有效决策点满足下凸包性质。

这道题我居然把一处Y(j)写成了(j),WA了许多次,真是够了。粗心害死人,一定要细心一点。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 #define MAXN 105
 6 int f[MAXN],w[MAXN],sum[MAXN],que[MAXN],head,tail,last;
 7 struct zhu
 8 {
 9     int sum,w;
10 }arr[MAXN];
11 int X(int i)
12 {
13     return arr[i].sum;
14 }
15 int Y(int i)
16 {return f[i];
17 }
18 bool turnup(int i,int j,int k)
19 {
20     if((X(j)-X(k))*(long long)(Y(i)-Y(j))>(X(i)-X(j))*(long long)(Y(j)-Y(k)))
21         return 1;
22         else return 0;
23 }
24 int main()
25 {
26     int t,n;
27     scanf("%d",&t);
28     while(t--)
29     {
30         head=tail=1;
31         last=0;
32         que[tail++]=0;
33         f[0]=0;
34         arr[0].sum=0,arr[0].w=0;
35         scanf("%d",&n);
36         for(int i=1;i<=n;i++)
37         {scanf("%d %d",&arr[i].sum,&arr[i].w);
38          arr[i].sum+=arr[i-1].sum;
39         }
40         for(int i=1;i<=n;i++)
41         {
42             while(head<tail-1&&Y(que[head+1])-Y(que[head])<=arr[i].w*(long long)(X(que[head+1])-X(que[head])))
43                 head++;
44             int best=que[head];
45             f[i]=f[best]+(arr[i].sum-arr[best].sum+10)*(long long)arr[i].w;
46             while(head<tail-1&&turnup(i,que[tail-1],que[tail-2])==0)
47                 tail--;
48             que[tail++]=i;
49         }
50         printf("%d
",f[n]);
51     }
52 }
View Code
原文地址:https://www.cnblogs.com/hefenghhhh/p/4597612.html