ZOJ 1013 Great Equipment(DP)

賈樹丙發表於2013-07-30

題目連結http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=13

題目大意:說的是有三種不同的裝備,分別是頭盔,盔甲,戰靴需要運輸,每種裝備擁有不同的重量,體積,以及防禦能力.當三種裝備按照一定的數量規定組合成套裝時,套裝可以發揮處更強的攻擊能力.然後有n個運輸車,每個車能夠運送的重量和體積有限制,現在問如何給這個n個運輸車分配運送任務(即每個運輸隊運多少頭盔,多少盔甲,多少戰靴) 可以獲得總的防禦值最大。

輸入描述:第一行是運輸車的數量n。接下來是第1行是每個頭盔的重量w1、體積s1、防禦能力d1;第2行是每個盔甲的重量w2、體積s2、防禦能力d2;第3行是每個戰靴的重量w3、體積s3、防禦能力d3;第4行是每個c1頭盔,c2個盔甲,c3個戰靴組成的套裝的防禦能力d4。接下來的n行每行2個整數,分別表示每個運輸車能承受的最大重量和體積。

Sample Input


3
1 1 3
5 6 10
2 1 2
1 1 1 50
1 1
5 6
2 1
0

Output for the Sample Input


Case 1: 50

分析:能把複雜度降下來的就可以稱為DP。

法1:由於套裝威力強,我們應該湊出儘量多的套裝然後再單算剩餘裝備的防禦力.因此在運輸的頭盔數,盔甲數一定時要使運輸的戰靴數儘可能地多。

1、G++下,至少在dp型陣列中,用memset、和memcpy函式的效率不如用迴圈初始化、複製快
2、此題以dp[i][j]儲存拿了 i 件頭盔(a武器),j 件盔甲(b武器)時能拿的最大的戰靴(c武器)的數量
3、最後一個狀態(最後一個車到達)後,用compute函式計算分別拿了各種數
量的三種武器後,能達到的防禦力,從中挑選最大的

 法2:網上很多人的思路都是設f[i][n1][n2]表示用前i量車子在運 n1件1武器和n2件2武器的條件下能運的第3種武器的最大數量。

  那麼f[0][0][0]=0設函式num(i,j,k)表示第i量車子在運j個1武器和k個2武器後最多再能運k個3武器,則f[i][n1][n2]=f[i-1][n3][n4]+num(i,n1-n3,n2-n4)

  f[i]的值只於f[i-1]有關,那麼可以用滾動陣列來節省空間

   本以為是揹包,牛們居然用列舉做出來了

法1程式碼如下:

 

 1 # include<stdio.h>
 2 # include<memory.h>
 3 # define MAXN 501
 4 int dp[MAXN][MAXN],dp2[MAXN][MAXN];
 5 int car[2][100];    //car[0][i]、car[1][i] 分別表示第i輛車的能承受的重量、體積
 6 int n;    //車的數量
 7 int w1,w2,w3,s1,s2,s3,c1,c2,c3,d1,d2,d3,d4;
 8 
 9 int min(int a,int b){
10     return a<b ? a :b;
11 }
12 
13 int compute(int a,int b,int c){    //計算防禦能力
14     int minnum;
15     minnum = min(min(a/c1,b/c2),c/c3);
16     return (minnum * d4 + (a- minnum*c1)*d1 + (b- minnum*c2)*d2 + (c- minnum*c3)*d3);
17 }
18 
19 int main(){
20     int i,j,k,cas=0,x,y;
21         int curr_a,curr_b; //分別表示所有車全部裝頭盔、全部裝盔甲 的最大數量
22         while(scanf("%d",&n)==1 && n){
23             scanf("%d%d%d%d%d%d%d%d%d%d%d%d%d",
24                 &w1, &s1, &d1,
25                 &w2, &s2 ,&d2,
26                 &w3, &s3, &d3,
27                 &c1, &c2, &c3, &d4);
28             for(i=0;i<n;i++) scanf("%d%d",&car[0][i],&car[1][i]);
29             for(i=0; i<MAXN; i++)
30                 for(j=0; j<MAXN; j++)
31                     dp[i][j] = dp2[i][j] = -1;
32             curr_a = curr_b = 0;
33             dp2[0][0] = 0;
34             k = 0;
35             while(k < n){
36                 for(i=0; i<= curr_a; i++)
37                     for(j=0; j<=curr_b; j++){
38                         dp[i][j] = dp2[i][j];
39                         dp2[i][j] = -1;
40                     }
41                     int r_a =min(car[0][k] / w1, car[1][k] / s1);    //該車能夠裝頭盔數量的最大值
42                     for(i=0; i<=r_a; i++)
43                     {
44                         int r_aw = car[0][k] - i * w1;    //裝了頭盔後剩下的總重量
45                         int r_as = car[1][k] - i * s1;    //裝了頭盔後剩下的總體積
46                         int r_b = min(r_aw / w2, r_as / s2);    //該車剩下部分能夠裝盔甲數量的最大值
47                         for(j=0; j<=r_b; j++)
48                         {
49                             int r_bw = r_aw - j * w2;    //再裝盔甲後剩下的總重量
50                             int r_bs = r_as - j * s2;    //再裝盔甲後剩下的總體積
51                             int r_c = min(r_bw / w3,r_bs/s3);    //該車剩餘部分最多能裝戰靴的數量
52                             for(x=0; x<=curr_a; x++)
53                                 for(y=0; y<=curr_b; y++)
54                                     if(dp[x][y] >=0 && dp[x][y] + r_c >dp2[x+i][y+j])
55                                         dp2[x+i][y+j] = dp[x][y] +r_c;
56                         }
57                     }
58                     curr_a += min(car[0][k] / w1, car[1][k] / s1);
59                     curr_b += min(car[0][k] / w2, car[1][k] / s2);
60                     k++;
61             }
62             int ans =0;
63             for(i=0; i<=curr_a; i++)
64                 for(j=0; j<=curr_b; j++)
65                 if(dp2[i][j] != -1){
66                     int temp = compute(i,j,dp2[i][j]);
67                     if(temp > ans) ans = temp;
68                 }
69             if(cas>0) puts("");
70             printf("Case %d: %d\n", ++cas, ans);
71         }
72         return 0;
73 }

 

 

 

相關文章