信息学奥赛一本通(1225:金银岛)
1225:金銀島
時間限制: 1000 ms ??? ??? 內存限制: 65536 KB
提交數: 8123 ??? 通過數: 4334
【題目描述】
某天KID利用飛行器飛到了一個金銀島上,上面有許多珍貴的金屬,KID雖然更喜歡各種寶石的藝術品,可是也不拒絕這樣珍貴的金屬。但是他只帶著一個口袋,口袋至多只能裝重量為w的物品。島上金屬有s個種類, 每種金屬重量不同,分別為n1,n2,...,ns,同時每個種類的金屬總的價值也不同,分別為v1,v2,...,vs。KID想一次帶走價值盡可能多的金屬,問他最多能帶走價值多少的金屬。注意到金屬是可以被任意分割的,并且金屬的價值和其重量成正比。
【輸入】
第1行是測試數據的組數k,后面跟著k組輸入。
每組測試數據占3行,第1行是一個正整數w(1≤w≤10000),表示口袋承重上限。第2行是一個正整數s(1≤s≤100),表示金屬種類。第3行有2s個正整數,分別為n1,v1,n2,v2,...,ns,vs分別為第一種,第二種,...,第s種金屬的總重量和總價值(1≤ni≤10000,1≤vi≤10000)。
【輸出】
k行,每行輸出對應一個輸入。輸出應精確到小數點后2位。
【輸入樣例】
2 50 4 10 100 50 30 7 34 87 100 10000 5 1 43 43 323 35 45 43 54 87 43【輸出樣例】
171.93 508.00【分析】
? ? ? ? 給定一個載重為M的背包,及n個重量為wi、價值為pi 的物體,要求把物品裝滿背包,且使背包內的物體價值最大,這類問題稱為背包問題。有兩類背包問題,即物體可以分割的背包問題,及物體不可分割的背包問題,我們把后者稱為0/1背包問題,由0/1背包還可以延伸出很多背包問題。前者為可分割的背包問題,可以用貪心算法求解。貪心的策略是拿性價比高的物體。這一點也好理解,我們去超市免費拿東西,你挑最貴的拿,拿走一臺冰箱,顯然是傻蛋。如果物品可以分割,你當然應該去拿性價比高的物品,冰箱固然貴重,但其性價比并不貴,你應該直接奔金銀首飾專柜去拿,金項鏈、翡翠這些都是性價比高的東西。
? ? ? ? 以樣例為例,我們來看求解過程。步驟為三步,分別是:
(1)求性價比
(2)按性價比,從大到小排序
(3)拿走最大價值
? ? ? ? 從前到后物品開始拿,拿的策略是先拿性價比高的。如果當前背包重量 > 某個物品的總重量,那別客氣,全拿走;否則,當前背包不足以拿走某個物品,那就能拿多少拿多少。樣例數據,第一組,背包承重50,則先把第一個物品(性價比為10的)全拿走,價值=100,背包重量=40。同理,再把第二個物品全拿走,價值=134,背包重量=33,拿第三個,不足以全拿走,只能拿33,價值=134+33*1.15=171.93
【參考代碼】
#include<stdio.h> #include<string.h> #define N 110 struct goods {int n; //總重量 double v; //總價值 double p; //性價比 }gds[N],tmp;int main() {int t,i,j;int w; //口袋承重上限 int s; //金屬種類 double sum=0; //最多帶走的價值 scanf("%d",&t);while(t--){sum=0;memset(gds,0,sizeof(gds));scanf("%d%d",&w,&s);for(i=0;i<s;i++){ scanf("%d%lf",&gds[i].n,&gds[i].v);gds[i].p = gds[i].v / gds[i].n;}for(i=0;i<s-1;i++) // 貪心策略是選性價比大的,按照性價比排序{for(j=i+1;j<s;j++){if(gds[i].p<gds[j].p){tmp=gds[i];gds[i]=gds[j];gds[j]=tmp;}}}for(i=0;i<s;i++) //枚舉每件物品{if(w>gds[i].n) //背包承重大于某物品的總重量,全拿走 {sum+=gds[i].v;w-=gds[i].n;}else //背包承重小于某物品的總重量,切割物品,能拿多少拿多少 {sum+=gds[i].p*w;w=0;}}printf("%.2lf\n",sum);}return 0; }http://ybt.ssoier.cn:8088/problem_show.php?pid=1225
總結
以上是生活随笔為你收集整理的信息学奥赛一本通(1225:金银岛)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 信息学奥赛一本通(1260:【例9.4】
- 下一篇: 信息学奥赛一本通 1041:奇偶数判断