刷题时间:2019/4/16
hdoj1300题目大意:
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1300
一个老哥要买珍珠,然后又想要花最少的钱买珍珠,然后珍珠卖家很奇怪,在每次买一种珍珠的时候为了防止你买的少就要加上十个数量作为手续费,然后这个老哥就想了一个方法,可以用高等级的珍珠来充当低等级的珍珠,然后输入的珍珠后面的是高等级的 前面是低等级的,意思就是可以用后面的珍珠来充当前面的珍珠,使之让总共花的钱最少。
从这个题目大意 我们就能得出 这是一个简单明显的dp 的题
我们只需要建一个dp[i]数组,用来表示买i个珍珠需要的最少金钱
废话不多说: 状态转移方程: 初始化dp[1]=(see[1]+10)*b[1] 表示买第一个等级需要花的钱
see数组表示前面i个种类珍珠的总共数量 这里用到了前缀和 see[i]=see[i-1]+a[i] 后面我会详细的讲解一下前缀和
前缀和 其实也没什么神奇的 就是能在O(1) 的复杂度下 求出在一个序列中第i个到第j个数的和 sum[j]-sum[i]
扯远了..... 不好意思
状态转移方程: dp[i]=min(dp[i],dp[j]+(see[i]-see[j]+10)*b[i]) 这里see[i] 表示的是前i种的总数 see[j]是从1到i 进行查找是否存在把低等级珍珠换成高等级的珍珠使之总花费dp[i] 更低的出现 有就更新
有了状态转移方程就方便啦 最后dp[n] 就表示第n种需要花的最少钱
代码如下
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define db double
#define MAX 100000
#define rep(i,j,k) for(int i=(int)(j);i<=(int)(k);i++)
#define per(i,j,k) for(int i=(int)(j);i>=(int)(k);i--)
int a[MAX],b[MAX];
int dp[MAX * 2];
int see[MAX];
void solve()
{
int c;
cin >> c;
memset(see, 0, sizeof(see));
rep(i, 1, c) {
cin >> a[i] >> b[i];
see[i] = see[i - 1] + a[i];
}
//初始化 第一行都是全部买本质量的珍珠
dp[1] = (see[1] + 10)*b[1];
rep(i, 2, c) {
dp[i] = (see[i] + 10)*b[i];
rep(j, 1, i-1) {
dp[i] = min(dp[i], dp[j] + (see[i] - see[j]+10)*b[i]);
//让前面的 see[i-1]-see[j]的全部数量用b[i] 的价格买
}
}
cout << dp[c] << endl;
}
int main()
{
int t;
cin >> t;
while (t--)
{
solve();
}
//system("pause");
return 0;
}