题目描述
在珍珠岛,珍珠被分为100个不同的等级。一个等级是由该等级的一颗珍珠的价格来确定的。这个价格对该等级来说是唯一的,而且这个价格总是高于低等级珍珠的价格。
每个月,库存经理都会准备一份清单,列出每个等级所需的珍珠数量。每个等级的珍珠都有自己的价格,但每完成一个特定等级的交易,就必须额外支付相当于该等级10颗珍珠的钱。这是为了防止游客只买一颗珍珠。
库存经理发现,他有时可以通过购买比实际需要的更高质量的珍珠来节省资金。在相同或更低的价格买到更高品质的珍珠,当然是一件欢喜的事情。
例如,在 10 10 10 欧元的类别中需要 5 5 5 颗珍珠,在 20 20 20 欧元的类别中需要 100 100 100 颗珍珠。这通常需要花费: ( 5 + 10 ) ∗ 10 + ( 100 + 10 ) ∗ 20 = 2350 (5+10)* 10+(100+10)* 20=2350 (5+10)∗10+(100+10)∗20=2350 欧元。购买 20 20 20 欧元类别的所有 105 105 105 颗珍珠只需要花费: ( 5 + 100 + 10 ) ∗ 20 = 2300 (5+100+10)*20=2300 (5+100+10)∗20=2300 欧元。
问题是库存经理想实现这样的操作,需要进行大量的计算工作。你被要求用一个计算机程序来帮助库存经理。
给出一个包含珍珠数量和不同等级的每颗珍珠价格的清单,给出购买清单上所有珍珠所需的最低价格。珍珠可以按要求购买,也可以按更高的质量等级购买,但不能按更低的等级购买。
输入格式
输入的第一行为测试案例的数量。
每个测试案例都以包含类别数量 c c c 的一行开始 ( 1 ≤ c ≤ 100 ) (1\leq c\leq 100) (1≤c≤100)。
接下来是 c c c 行,每行有两个数字 a i a_i ai 和 p i p_i pi。其中,第一个数字为一个类别中需要的珍珠数量 a i a_i ai ( 1 ≤ a i ≤ 1000 ) (1\leq a_i\leq 1000) (1≤ai≤1000)。第二个数字是该等级中每颗珍珠的价格 p i p_i pi ( 1 ≤ p i ≤ 1000 ) (1 \leq pi \leq 1000) (1≤pi≤1000)。
各个等级的价格是按升序排列的。输入的所有数字都是整数。
输出格式
对于每个测试案例,输出一个整数,表示购买清单上所有东西所需的最低价格。
样例输入
2
2
100 1
100 2
3
1 10
1 11
100 12
样例输出
330
1344
提交链接
http://poj.org/problem?id=1260
提示
对于
3
1 10
1 11
100 12
正常花费:
(
1
+
10
)
∗
10
+
(
1
+
11
)
∗
10
+
(
100
+
10
)
∗
12
=
1551
(1+10)*10+(1+11)*10+(100+10)*12=1551
(1+10)∗10+(1+11)∗10+(100+10)∗12=1551,花费
1551
1551
1551。
若把第一种归到第二种:
(
2
+
10
)
∗
11
+
(
100
+
10
)
∗
12
=
1452
(2+10)*11+(100+10)*12=1452
(2+10)∗11+(100+10)∗12=1452,花费
1452
1452
1452。
若把第一种,第二种归到第三种:
(
102
+
10
)
∗
12
=
1344
(102+10)*12=1344
(102+10)∗12=1344,花费
1344
1344
1344。
所以正确的选择是第三种的购买 102 102 102 颗,花费的钱少,品质也更高。
解析
通过上面可以看出,求组合的每一种状态的最小值。
dp[i]:购买前
i
i
i(包括
i
i
i)种商品,所花费的最少金额。
1.初始化:刚开始的状态,是各买各的,有 i i i 类珍珠,就分 i i i 次购买
for(int i=1; i<=c; i++)
{
cin>>a[i]>>p[i]; //数量 价格
sum[i]=sum[i-1]+a[i];
dp[i]=dp[i-1]+(a[i]+10)*p[i]; //初始状态
}
2.然后通过状态迁移,找出最小的。
for(int i=1; i<=c; i++) //状态转移
{
for(int j=0; j<i; j++)
dp[i]=min(dp[i],dp[j]+(sum[i]-sum[j]+10)*p[i]);
}
参考代码
#include<bits/stdc++.h>
using namespace std;
int a[102],p[102],sum[102],dp[102];
int c,t;
int main()
{
cin>>t; //t组样例
while(t--)
{
memset(sum,0,sizeof(sum)); //前i类珍珠的数量总和
memset(dp,0,sizeof(dp)); //购买前i(包括i)种商品,所花费的最少金额
cin>>c; //c种珍珠
for(int i=1; i<=c; i++)
{
cin>>a[i]>>p[i]; //数量 价格
sum[i]=sum[i-1]+a[i];
dp[i]=dp[i-1]+(a[i]+10)*p[i]; //初始状态
}
for(int i=1; i<=c; i++) //状态转移
{
for(int j=0; j<i; j++)
dp[i]=min(dp[i],dp[j]+(sum[i]-sum[j]+10)*p[i]);
}
cout<<dp[c]<<endl;
}
return 0;
}