經營與開發 DP

問題描述

你駕駛着一臺帶有鑽頭(初始能力值w)的飛船,按既定路線依次飛過n個星球。

星球籠統的分爲2類:資源型和維修型。(p爲鑽頭當前能力值)

資源型:含礦物質量a[i],若選擇開採,則得到a[i]p的金錢,之後鑽頭損耗k%,即p=p(1-0.01k)
維修型:維護費用b[i],若選擇維修,則支付b[i]p的金錢,之後鑽頭修復c%,即p=p(1+0.01c)
注:維修後鑽頭的能力值可以超過初始值(你可以認爲是翻修+升級)

請作爲艦長的你仔細抉擇以最大化收入。

輸入格式

第一行4個整數n,k,c,w。

以下n行,每行2個整數type,x。

type爲1則代表其爲資源型星球,x爲其礦物質含量a[i];

type爲2則代表其爲維修型星球,x爲其維護費用b[i];

輸出格式

一個實數(保留2位小數),表示最大的收入。

樣例輸入

5 50 50 10
1 10
1 20
2 10
2 20
1 30

樣例輸出

375.00

數據範圍

對於30%的數據 n<=100

另有20%的數據 n<=1000;k=100

對於100%的數據 n<=100000; 0<=k,c,w,a[i],b[i]<=100;保證答案不超過10^9


首先說一下O(n3) 的暴力做法:

定義f[i][j][k] 表示討論完第i個數,維修j次,開採k次所能得到的最大收入。那麼顯然有狀態轉移方程:

f[i][j][k]=max(f[i1][j][k],f[i1][j][k1]+a[i]p),type[i]=1
f[i][j][k]=max(f[i1][j][k],f[i1][j1][k]b[i]p),type[i]=2

其中p 爲該狀態下的鑽頭能力值。f[0][0][0]=0

然而這樣只能得30分。考慮O(n) 或者是O(nlogn) 的做法。


事實上,這道題的正解有點費用提前計算的感覺。其實也是一個常見的思路:如果正着討論不夠優秀或者難以討論,考慮倒着討論。注意到如果把答案列式計算下來,可以發現一個乘法分配率的形式,因爲每次操作對p 的改變都是乘上一個數。所以,如果定義f[i] 爲處理完區間[i,n] 的星球得到的最大收入,那麼有:

f[i]=max(f[i+1],(10.01k)f[i+1]+a[i]),type[i]=1
f[i]=max(f[i+1],(1+0.01c)f[i+1]b[i]),type[i]=2

最後的答案就是Wf[1] ,時間複雜度O(n)

#include<stdio.h>
#include<algorithm>
#define MAXN 100005
using namespace std;

int N,ty[MAXN];
double K,C,W,v[MAXN],f[MAXN];

int main()
{
    int i;

    scanf("%d%lf%lf%lf",&N,&K,&C,&W);

    for(i=1;i<=N;i++)scanf("%d%lf",&ty[i],&v[i]);

    for(i=N;i>=1;i--)
    {
        if(ty[i]==1)f[i]=max(f[i+1],f[i+1]*(1-K/100)+v[i]);
        else f[i]=max(f[i+1],f[i+1]*(1+C/100)-v[i]);
    }   

    printf("%.2lf",W*f[1]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章