pku 1260 Pearls 简单DP
http://poj.org/problem?id=1260
题意是:给定不同级别不同价值的珍珠,问如果购买所有的珍珠最少花费。每买一种价格的珍珠就要多付10个钱。其中低等的珍珠可以用高等的珍珠进行替代
才开始自己想的是对于当前等级i的珍珠要么只买这一等级的珍珠,要么用这一等级的珍珠替换所有比他低级的珍珠以求得购当前(a[1]+a[2]+a[3] +....+a[i])数量珍珠的最少费用,样例过了可是WA后来想了想对于当前状态比他低级的不应定非要用它替换,我们只要最小就可以了,如果这要对于i后面的状态(情况特别多)就不好处理了。最后看了一下discuss有人证明了,只要枚举比i低级的连续的等级用i替换求出最小就可以了。
状态转移方程dp[i] = min(dp[i] ,dp[j] + (p[j].ai + p[j + 1].i + ..... + p[i].ai + 10)*p[i].pi) (0<= j <=i) dp[i]表示购买前i个等级的所有珍珠的最少花费
证明如下:
首先证明最优解中肯定不会有交叉的替换,即在质量为a<b<j<c<d的情况下,如果a被c替换,那么b也一定要被c替换 假设在最优解中存在:a被c替换且b不被c替换的情况: 1.b不被任何替换 那么此时把a换成用b替换 得到比原来更优的解,错误 2.b被j替换,此时把a换成用j替换 得到比原来更优的解,错误 3.b被d替换,此时把b换成用c替换 得到比原来更优的解,错误 因此,不存在交叉的替换,
View Code
#include <iostream> #include <cstring> #include <cstdio> #define maxn 107 #define inf 99999999 using namespace std; int c; struct node { int ai; int pi; }p[maxn]; int dp[maxn]; int main() { //freopen("in.txt","r",stdin); int t,i,j; scanf("%d",&t); while (t--) { scanf("%d",&c); for (i = 1; i <= c; ++i) scanf("%d%d",&p[i].ai,&p[i].pi); for (i = 0;i <= c; ++i) dp[i] = inf; dp[0] = 0; for (i = 1; i <= c; ++i) { int sum = p[i].ai; for (j = i - 1; j >= 0; --j) { dp[i] = min(dp[i],dp[j] + (sum + 10)*p[i].pi); sum += p[j].ai; } } printf("%d\n",dp[c]); } return 0; }