題目背景
由於你的幫助,火星只遭受了最小的損失。但gw懶得重建家園了,就造了一艘飛船飛向遙遠的earth星。不過飛船飛到一半,gw發現了一個很嚴重的問題:肚子餓了~
gw還是會做飯的,於是拿出了儲藏的食物準備填飽肚子。gw希望能在T時間內做出最美味的食物,但是這些食物美味程度的計算方式比較奇葩,於是絕望的gw只好求助於你了。
題目描述
一共有n件食材,每件食材有三個屬性,ai,bi和ci,如果在t時刻完成第i樣食材則得到ai-t*bi的美味指數,用第i件食材做飯要花去ci的時間。
衆所周知,gw的廚藝不怎麼樣,所以他需要你設計烹調方案使得美味指數最大
輸入格式
第一行是兩個正整數T和n,表示到達地球所需時間和食材個數。
下面一行n個整數,ai
下面一行n個整數,bi
下面一行n個整數,ci
輸出格式
輸出最大美味指數
輸入輸出樣例
輸入 #1
74 1 502 2 47
輸出 #1
408
說明/提示
【數據範圍】
對於40%的數據1<=n<=10
對於100%的數據1<=n<=50
所有數字均小於100,000
【題目來源】
tinylic改編
思路: 這題有點類似於揹包問題取最大價值的類型。但不同點是本題中食物的美味程度與時間相關,是會一直變化的;而揹包問題中物品的價值是固定的。那麼可不可以通過某些特定的表達式來計算食材相對固定的價值呢?單看一份食材是沒有結論的,那麼我們可以設置x、y兩份相鄰的食材(暫時只考慮這兩份食材,它倆的製作順序是相鄰的,但是誰先誰後不確定),該做這兩份食材時時間已經過去了t。食材的a、b、c存儲在結構體數組q中。
可以有先做x的美味程度sum1=q[x].a-(t+q[x].c)*q[x].b+q[y].a-(t+q[x].c+q[y].c)*q[y].b
先做y的美味程度sum2=q[y].a-(t+q[y].c)*q[y].b+q[x].a-(t+q[y].c+q[x].c)*q[x].b
如果令sum1>sum2則化簡得:q[x].c*q[y].b<q[y].c*q[x].b 發現只要滿足這個條件的物品對(x,y),x在y前的代價永遠更優。然後可是重載下結構體數組的cmp函數,進行排序,根據這個排序結果,解決問題。因爲題目中有時間限制,所以狀態轉移關係應該與時間有關。設已用時間j,i爲當前遍歷到的食材編號,則有狀態轉移方程爲
if(dp[j]>0&&j+q[i].c<=T){
dp[j+q[i].c]=max( dp[j+q[i].c] , dp[j] + (LL)q[i].a - (LL)(j+q[i].c) *(LL)q[i].b);
}代碼如下:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn=51;
const int maxs=100001;
LL dp[maxs];
struct node{
int a,b,c;
}q[maxn];
bool cmp(node a,node b)
{
return (LL)a.c*(LL)b.b<(LL)a.b*(LL)b.c;
}
int main()
{
int T,n;
LL sum=0;
scanf("%d %d",&T,&n);
for(int i=0;i<n;i++)scanf("%d",&q[i].a);
for(int i=0;i<n;i++)scanf("%d",&q[i].b);
for(int i=0;i<n;i++)scanf("%d",&q[i].c);
sort(q,q+n,cmp);
memset(dp,255,sizeof(dp));//初始化很重要
dp[0]=0;
for(int i=0;i<n;i++){
for(int j=T;j>=0;j--)
{
if(dp[j]>0&&j+q[i].c<=T){//這樣在保證時間合法的情況下使每個時間完成的食物的美味程度和儘可能大,至於用哪些食材作出來的並不用關心
dp[j+q[i].c]=max(dp[j+q[i].c],dp[j]+(LL)q[i].a-(LL)(j+q[i].c)*(LL)q[i].b);
}
}
}
for (int i = 0; i <= T; i++)sum = max(sum, dp[i]);//遍歷dp數組,得到最大的美味程度
cout << sum << endl;
return 0;
}