1. 程式人生 > >金明的預算(01揹包問題)---------Five-菜鳥級

金明的預算(01揹包問題)---------Five-菜鳥級

                                                             金明的預算

問題描述

  金明今天很開心,家裡購置的新房就要領鑰匙了,新房裡有一間金明自己專用的很寬敞的房間。 更讓他高興的是,媽媽昨天對他說:“你的房間需要購買哪些物品,怎麼佈置,你說了算, 只要不超過N元錢就行”。今天一早,金明就開始做預算了,他把想買的物品分為兩類: 主件與附件,附件是從屬於某個主件的,下表就是一些主件與附件的例子:

主件 附件  電腦 印表機,掃描器  書櫃 圖書  書桌 檯燈,文具  工作椅 無 

  如果要買歸類為附件的物品,必須先買該附件所屬的主件。每個主件可以有0個、1個或2個附件。 附件不再有從屬於自己的附件。金明想買的東西很多,肯定會超過媽媽限定的N元。於是, 他把每件物品規定了一個重要度,分為5等:用整數1~5表示,第5等最重要。他還從因特網上查到了每件物 品的價格(都是10元的整數倍)。他希望在不超過N元(可以等於N元)的前提下,使每件物品的價格與 重要度的乘積的總和最大。    設第j件物品的價格為v[j],重要度為w[j],共選中了k件物品,編號依次為j_1,j_2,……,j_k,  則所求的總和為:    v[j_1]*w[j_1]+v[j_2]*w[j_2]+ …+v[j_k]*w[j_k]。(其中*為乘號)    請你幫助金明設計一個滿足要求的購物單。 輸入格式

  輸入檔案budget.in 的第1行,為兩個正整數,用一個空格隔開:    N m   (其中N(<32000)表示總錢數,m(<60)為希望購買物品的個數。)    從第2行到第m+1行,第j行給出了編號為j-1的物品的基本資料,每行有3個非負整數    v p q   (其中v表示該物品的價格(v<10000),p表示該物品的重要度(1~5), q表示該物品是主件還是附件。如果q=0,表示該物品為主件,如果q>0,表示該物品為附件, q是所屬主件的編號)

輸出格式

  輸出檔案budget.out只有一個正整數,為不超過總錢數的物品的價格與重要度乘積的總和的 最大值 (<200000)。

樣例輸入

1000 5  800 2 0  400 5 1  300 5 1  400 3 0  500 2 0

樣例輸出

2200

思路: 按主件選取 在有主件的情況下選取附件 題知 附件最多兩個 所以 一個主 可 0,1,2個附件 分情況討論  從而轉化為 01 揹包問題 

#include<stdio.h>
 long int Max(long int a,long int b)
 {if(a>b)return a;
 else return b;
 }
int main()
{
long int w[100], v[100], z1[100]={0},z2[100]={0},q[100]={0};
     //存重要度    存價格           存元件1      存元件2      存商品性質 0代表主件 
long int dp[100][3201]={0};//dp[i][j]=k 代表 
int i,j,n,m;
scanf("%d%d",&m,&n);
 m/=10;//初始化 資料縮小10倍 (因為題目說了都是10的整數倍) 
for(i=1;i<=n;i++)
 {scanf("%d%d%d",&v[i],&w[i],&q[i]);
   v[i]/=10;//資料縮小10倍 (因為題目說了都是10的整數倍) 
   if(q[i]!=0)//不是主件 
   {  if(z1[q[i]]==0) z1[q[i]]=i;//找到對應主件存 元件 1 
       else z2[q[i]]=i;
   }
 }
  v[0]=w[0]=q[0]=0;//揹包初始化 
  for(i=1;i<=n;i++)// 列舉物品數 
  for(j=1;j<=m;j++)//列舉錢數 
  if(v[i]<=j&&q[i]==0)//判斷主件 
  {
  	dp[i][j]=Max(dp[i-1][j],dp[i-1][j-v[i]]+v[i]*w[i]);//不配元件  單主件 
  	if(v[z1[i]]+v[i]<=j)dp[i][j]=Max(dp[i][j],dp[i-1][j-v[z1[i]]-v[i]]+v[i]*w[i]+v[z1[i]]*w[z1[i]]);//配 附件 1 
  	if(v[z2[i]]+v[i]<=j)dp[i][j]=Max(dp[i][j],dp[i-1][j-v[z2[i]]-v[i]]+v[i]*w[i]+v[z2[i]]*w[z2[i]]);//配 附件 2 
  	if(v[z1[i]]+v[z2[i]]+v[i]<=j)dp[i][j]=Max(dp[i][j],dp[i-1][j-v[z1[i]]-v[i]-v[z2[i]]]+v[i]*w[i]+v[z1[i]]*w[z1[i]]+v[z2[i]]*w[z2[i]]);//配兩附件 
  }else dp[i][j]=dp[i-1][j];//不取 

printf("%ld",dp[n][m]*10);

return 0;}