HDOJ 3401題目串連
告訴你 T 天裡,物品的買賣價格,和當天最多買賣數量,還有 T 天裡最多儲存物品數量,每一次買賣間隔時間必須大於 w+1
很容易想到DP【i】【j】表示,第i天結束的時候還儲存有j個物品時的最大獲利
初始化dp【i】【j】 = dp【i-1】【j】;
那麼狀態方程dp【i】【j】 = MAX(dp【k】【j】),其中k<= i - w - 1;
且有 dp【i】【j】=MAX(dp【k】【z】 - (j - z) * buyValue【i】),其中,k<=i-w-1,z<j且 z>=j-maxBuy【i】;
還有 dp【i】【j】=MAX(dp【k】【z】 + (z - j) * sellValue【i】),其中,k<=i-w-1,z>j且 z<=j + maxSell【i】;
所以會有i,j,z三層迴圈,而他們的範圍都是2000,所以有2000^3的複雜度,肯定逾時
這個時候我們可以用優先隊列來最佳化,使之少一層迴圈
z<j且 z>=j-maxBuy【i】的時候,dp【i】【j】= dp【k】【z】 - (j - z) * buyValue【i】= dp【k】【z】 + z * buyValue【i】 - j*buyValue【i】
可以發現dp【k】【z】 + z * buyValue【i】部分只與z有關;
- j*buyValue【i】而後面的部分只與j有關,所有z都一樣;
所以我們需要的是式子前面這一部分的值越大越好,而z的範圍又隨著j的變化而變化,剛好是優先隊列的使用方式
這個題目有注意的地方
(1)就是k可以定為i-w-1,因為i-w-1之前的所有並沒有比i-w-1優,相反i-w-1這一天有可能比前面的優
(2)別忘了i可以從i-1天來
(3)最後的答案其實一定是剩餘0個物品的時候
My Code:
#include<stdio.h>
//#include<string.h>
//#include<algorithm>
#define CANNOT (-0x3fffffff)
#define MAX 2100
int dp[MAX][MAX];
int days[MAX][4];
int que[MAX], tail, front;
int where[MAX];
int t, maxp, w;
int Max(int a, int b)
{
return a > b ? a : b;
}
int main()
{
int i, j;
int cases;
int result;
int xx;
scanf("%d", &cases);
while(cases --)
{
result = 0;
scanf("%d%d%d", &t, &maxp, &w);
for(i = 1; i <= t; i ++)
{
scanf("%d%d%d%d", &days[i][0], &days[i][1], &days[i][2], &days[i][3]);
}
for(i = 1; i <= t; i ++)
{
if(i <= w + 1)
{
for(j = 0; j <= maxp; j ++)
{
if(j <= days[i][2])
{
dp[i][j] = -j * days[i][0];
}
else
{
dp[i][j] = CANNOT;
}
if(i > 1)
dp[i][j] = Max(dp[i][j], dp[i - 1][j]);
}
}
else
{
for(j = 0; j <= maxp; j ++)
{
dp[i][j] = dp[i - w - 1][j];
dp[i][j] = Max(dp[i][j], dp[i - 1][j]);
}
tail = -1;
front = 0;
int temp = 0;
for(j = 0; j <= maxp; j ++)
{
while(temp < j)
{
if(dp[i - w - 1][temp] == CANNOT)
{
temp ++;
continue;
}
xx = dp[i - w - 1][temp] + temp * days[i][0];
while(front <= tail)
{
if(xx >= que[tail])
tail --;
else
break;
}
que[++ tail] = xx;
where[tail] = temp;
temp ++;
}
while(front <= tail && j - where[front] > days[i][2])
{
front ++;
}
if(front <= tail)
dp[i][j] = Max(dp[i][j], que[front] - j * days[i][0]);
}
tail = -1;
front = 0;
temp = 0;
for(j = 0; j <= maxp; j ++)
{
while(temp <= j + days[i][3] && temp <= maxp)
{
if(dp[i - w - 1][temp] == CANNOT || temp <= j)
{
temp ++;
continue;
}
xx = dp[i - w - 1][temp] + temp * days[i][1];
while(front <= tail)
{
if(xx >= que[tail])
tail --;
else
break;
}
que[++ tail] = xx;
where[tail] = temp;
temp ++;
}
while(front <= tail && where[front] <= j)
{
front ++;
}
if(front <= tail)
dp[i][j] = Max(dp[i][j], que[front] - j * days[i][1]);
}
}
}
// result = 0;
// for(i = 0; i <= maxp; i ++)
// result = Max(result, dp[t][i]);
// printf("%d\n", result);
printf("%d\n", dp[t][0]);
}
return 0;
}