您的位置:首页 > 其它

POJ 1260--Pearls

2014-07-31 17:27 393 查看
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 0x7FFFFFFF

int 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: