題目連結: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 }