首页 > 代码库 > acm poj1260 dp

acm poj1260 dp

题目大意:

买珍珠,每买一种珍珠需要额外付出十个这种珍珠的钱,但你可以买比这种珍珠高品质的珍珠来替换它(那么就只需要那高品质付出那额外的十个珍珠的钱了,但是每个珍珠的价钱也变化了)

这是一个dp。

令dp[i]为只买前i种珍珠的最少花费钱数,

状态转移方程为dp[i] = min(dp[i],dp[j]+sum);

这里j<i, sum为j之后到i种珍珠均用第i种珍珠替换所需要的钱数;

sum是很好解决的。

那么有人问了,这个状态转移只能求第i种只替换前面连续种珍珠的情况,如果是像1和3都用第三种珍珠替换,而第二种自己买你的不就不能求了。也就是说如果某种珍珠需要替换前面不连续的几种的话怎么办呢?

现在我们来证明那种情况是不存在的。

我们设每种的价格为xi,每种需要买的个数为ni,每买一种需要额外付出的钱数为ci。

情况一为1,3种珍珠一起买,2珍珠单独买;

那么需要(n1+n3+10)*x3+(n2+10)*x2;

情况2为1,2种珍珠一起买,3珍珠单独买;

则需要(n3+10)*x3+(n1+n2+10)*x2;

如果情况一比情况2学要的钱数少,列不等式可得x3<=x2。

那么2种珍珠也应该用3来替换这样显然更省钱(少付了额外十个2种珍珠的钱);

所以1用3替换那么2就肯定也用3来替换;

推广起来;

如果某一种珍珠替换了前面不连续种珍珠为最优解;

那么就说明替换的最前面珍珠的后面那些没替换的珍珠的单价大于用来替换的珍珠的单价;

那么那些没替换的替换点显然为更优解,所以被替换的珍珠必然不能是不连续的,而且要紧挨着用来替换的珍珠;

证明完毕;

上代码;

#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int maxa = 105;
int sum[maxa];
int dp[maxa];
int a[maxa], b[maxa];
int main(){
int t, n;
scanf("%d", &t);
while(t--){
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d%d", &a[i], &b[i]);
sum[i] = sum[i-1] + a[i];
}
for(int i = 1; i <= n; i++){
int mina = (1<<29);
for(int k = 0; k < i; k++){
mina = min(mina, dp[k] +(sum[i] - sum[k]+10)*b[i]);
}
dp[i] = mina;
}
printf("%d\n", dp[n]);
}
}