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;
}