POJ 1260--Pearls

来源:互联网 发布:php数据表统计插件 编辑:程序博客网 时间:2024/05/16 11:49

DP问题:

首先想到了一个转移方程:minCost[i] = min{minCost[j]+(sumNum[i]-sumNum[j]+10)*price[i],0<=j<=i-1},但是想了一下好像没法证明和第i中珍珠一起买的珍珠必须是连续的,作罢。

又想了一个转移方程,首先按价格逆序输入:minCost[i] = minCost[i-1]+min{(needNum[i]+!IsUse[j]*10)*price[j],0<=j<=i},其中IsUse[j]代表第i种珍珠的价格是否已经用过了,结果WA了。

上面的转移方程只在当前最优,但是不满足无后效性。看似好像新输入的价格比已经求得结果的珍珠价格要低,所以只需要考虑把当前珍珠放在哪个高档次里面。但是如果当我们选定了当前珍珠的位置,可能将当前珍珠与后面的珍珠联合起来考虑它们放的位置就完全不一样了。

eg:

3
11 8
10 10
10 15

使用上面的方法,第一二种珍珠都会和第三种珍珠一起购买,结果615。但是其实第一二种珍珠一起购买会消费更少,结果610。

然后又回到第一个转移方程,证明连续性,反证:若与第i种珍珠购买的珍珠为i-k-1,i-k+1,...,i-1。即从i-k-1到i只有i-k单独购买,因为price[i] > price[i-k],则我们可知第i-k-1种珍珠和第i-k种珍珠会消费得更少,得证。


#include<cstring>#include<cstdio>#define maxC 101#define INF 0x7FFFFFFFint main(){    int i,j,T;    int kindNum;    short price[maxC],tmpNum;    int sumNum[maxC];    int minCost[maxC];    scanf("%d",&T);    while(T--)    {        sumNum[0] = 0;        scanf("%d",&kindNum);        for(i = 1;i <= kindNum;i++)        {            scanf("%hd%hd",&tmpNum,price+i);            sumNum[i] = sumNum[i-1]+tmpNum;        }        minCost[0] = 0;        for(i = 1;i <= kindNum;i++)        {            minCost[i] = INF;            for(j = 0;j < i;j++)            {                if(minCost[j]+(sumNum[i]-sumNum[j]+10)*price[i] < minCost[i])                    minCost[i] = minCost[j]+(sumNum[i]-sumNum[j]+10)*price[i];            }        }        printf("%d\n",minCost[kindNum]);    }    return 0;}


0 0