洛谷——背包型dp
1.P1417 烹調方案
題目背景
由於你的幫助,火星只遭受了最小的損失。但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改編
思路:
如果沒有b[i]這個屬性的話就是明顯的01背包問題。
現在考慮相鄰的兩個物品x,y。假設現在已經耗費p的時間,那麽分別列出先做x,y的代價:
a[x]-(p+c[x])*b[x]+a[y]-(p+c[x]+c[y])*by
a[y]-(p+c[y])*b[y]+a[x]-(p+c[y]+c[x])*bx
對這兩個式子化簡,得到①>②的條件是c[x]*b[y]<c[y]*b[x].
發現只要滿足這個條件的物品對(x,y),x在y前的代價永遠更優。
因此可以根據這個條件進行排序,之後就是簡單的01背包了。
(づ ̄3 ̄)づ╭?~ 代碼:
#include<iostream> #include<cstdio> #include<algorithm> usingnamespace std; int t,n; long long f[1000001],ans; struct Bag{ long long a,b,c; }eat[60]; int cmp(Bag X,Bag Y) { return Y.b*X.c < X.b*Y.c; } int main() { scanf("%d%d",&t,&n); for(int i=1; i<=n; i++) cin>>eat[i].a; for(int i=1; i<=n; i++) cin>>eat[i].b; for(int i=1; i<=n; i++) cin>>eat[i].c; sort(eat+1,eat+n+1,cmp); for(int i=1; i<=n; i++) { for(long long j=t; j>=eat[i].c; j--) { f[j]=max(f[j],f[j-eat[i].c]+eat[i].a-j*eat[i].b); } } for(int i=1; i<=t; i++) ans=max(ans,f[i]); cout<<ans<<endl; return 0; }
2.P1060 開心的金明
題目描述
金明今天很開心,家裏購置的新房就要領鑰匙了,新房裏有一間他自己專用的很寬敞的房間。更讓他高興的是,媽媽昨天對他說:“你的房間需要購買哪些物品,怎麽布置,你說了算,只要不超過N元錢就行”。今天一早金明就開始做預算,但是他想買的東西太多了,肯定會超過媽媽限定的N元。於是,他把每件物品規定了一個重要度,分為5等:用整數1~5表示,第5等最重要。他還從因特網上查到了每件物品的價格(都是整數元)。他希望在不超過N元(可以等於N元)的前提下,使每件物品的價格與重要度的乘積的總和最大。
設第j件物品的價格為v[j],重要度為w[j],共選中了k件物品,編號依次為j1,j2,……,jk,則所求的總和為:
v[j1]*w[j1]+v[j2]*w[j2]+ …+v[jk]*w[jk]。(其中*為乘號)
請你幫助金明設計一個滿足要求的購物單。
輸入輸出格式
輸入格式:
輸入的第1行,為兩個正整數,用一個空格隔開:
N m (其中N(<30000)表示總錢數,m(<25)為希望購買物品的個數。)
從第2行到第m+1行,第j行給出了編號為j-1的物品的基本數據,每行有2個非負整數
v p (其中v表示該物品的價格(v<=10000),p表示該物品的重要度(1~5))
輸出格式:
輸出只有一個正整數,為不超過總錢數的物品的價格與重要度乘積的總和的最大值(<100000000)。
輸入輸出樣例
輸入樣例#1:1000 5 800 2 400 5 300 5 400 3 200 2輸出樣例#1:
3900
說明
NOIP 2006 普及組 第二題
大水題一個 ~~~^_^~~~
(づ ̄3 ̄)づ╭?~ 代碼:
#include<iostream> #include<cstdio> using namespace std; int n,m,v[30001],num[50]; int f[30001]; int main() { scanf("%d%d",&n,&m); for(int i=1; i<=m; i++) { scanf("%d%d",&v[i],&num[i]); } for(int i=1; i<=m; i++) { for(int j=n;j>=v[i];j--) { f[j]=max(f[j],f[j-v[i]]+v[i]*num[i]); } } cout<<f[n]<<endl; return 0; }
3.P1926 小書童——刷題大軍
題目背景
數學是火,點亮物理的燈;物理是燈,照亮化學的路;化學是路,通向生物的坑;生物是坑,埋葬學理的人。 文言是火,點亮歷史宮燈;歷史是燈,照亮社會之路;社會是路,通向哲學大坑;哲學是坑,埋葬文科生。——小A
題目描述
小A“刷題”十分猖狂,明目張膽地“刷題”。他現在在小書童裏發現了n樣他喜歡的“題目”,每“題”都有他的需要時間,而老師布置了m項作業,每項作業都有它的需要時間及分值,老師規定k分以上算及格。小A只剩r個單位時間,他想在及格的基礎上更多地“刷題”。
輸入輸出格式
輸入格式:
第一行:n m k r。第二行:n個數,代表每“題”他的需要時間。第三行:m個數。表示每項作業它的需要時間。第四行:m個數。代表每項作業它的分值。
輸出格式:
一個數,代表小A能刷幾道題
輸入輸出樣例
輸入樣例#1:3 4 20 100 15 20 50 10 15 40 40 5 5 10 15輸出樣例#1:
2
說明
沒有不能及格的情況
思路:
用01背包求出做老師布置作業的最大分數,因為小A想要盡可能的多刷題,所以在老師布置作業一旦幾個以後立馬停止,剩余時間都用來刷題,要求刷題數目,所以從刷題所需時間最小的開始(排序)。。。
(づ ̄3 ̄)づ╭?~ 代碼:
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,m,k,r,tim; int ti[10001],tm[10001],fs[10001]; int f[10001]; int main() { scanf("%d%d%d%d",&n,&m,&k,&r); for(int i=1; i<=n; i++) scanf("%d",&ti[i]); for(int i=1; i<=m; i++) scanf("%d",&tm[i]); for(int i=1; i<=m ;i++) scanf("%d",&fs[i]); for(int i=1; i<=m; i++) { for(int j=r; j>=tm[i]; j--) { f[j]=max(f[j],f[j-tm[i]]+fs[i]); } } for(int i=1; i<=r;i++) if(f[i]>=k) { tim=r-i; break; } sort(ti+1,ti+n+1); int i=0; while(tim>=ti[i+1]){ i++; tim-=ti[i]; }cout<<i<<endl; return 0; }
自己選的路,跪著也要走完!!!
洛谷——背包型dp