POJ 1260 Pearls ACM解题报告(区间dp)

这题的题目好长啊,一开始也死活不理解,看了人家题解里的说明才懂了要干嘛,貌似小白上也有个类似的题,我也是不理解题目意思,现在懂了。

给你c种珍珠,每种珍珠要ai个,价格是pi,价格给你的时候就是递增的,所以不需要排序了,每种珍珠买的时候要多付10个同种珍珠的价钱,就是买一种珍珠需要的钱是(ai+10)*pi,然后为了减小支出,可以用贵的珍珠代替便宜的,比如用第j种代替第i种,他们的价格就从(ai+10)*pi+(aj+10)*pj变为了(ai+aj+10)*pj。

既然价格是递增排序的,就可以用区间dp求解了。首先这种珍珠不会跳过下一种,用下下一种代替,为什么呢?比如有i,j,k三种,如果你用k来代替i,假设费用减少了,就是减少了(ai+10)*pi-ai*pk,看着个公式,如果用j代替i,那么这个式子的答案会更大(pj<pk),所以代替必定是连续的,j代替i,或者k代替j和i,而不能j不变,k代替i。

说到这里,那么很简单了,有了状态转移方程就可以解决问题了:d[i]=min(d[j]+(sum[i]-sum[j])*val[i]);

#include<iostream>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<stack>
using namespace std;
#define MAX 105
typedef long long LL;
const double pi=3.141592653589793;
const int INF=1e9;
const double inf=1e20;
int a[105],sum[105],val[105];
int dp(int i)
{
    if(a[i]) return a[i];
    if(!i) return 0;
    int ans=INF;
    for(int k=0;k<i;k++) ans=min(ans,dp(k)+(sum[i]-sum[k]+10)*val[i]);
    return a[i]=ans;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int c,num;
        cin>>c;
        memset(a,0,sizeof(a));
        sum[0]=0;
        for(int i=1;i<=c;i++)
        {
            scanf("%d%d",&num,&val[i]);
            sum[i]=sum[i-1]+num;
        }
        printf("%d\n",dp(c));
    }
    return 0;
}


你可能感兴趣的:(动态规划,ACM,poj)