背包问题(一个以及无限个)
题目说明:
假設有一個背包的負重最多可達8公斤,而希望在背包中裝入負重範圍內可得之總價物品,假設是水果好了,水果的編號、單價與重量如下所示:
0 | 李子 | 4KG | NT$4500 |
1 | 蘋果 | 5KG | NT$5700 |
2 | 橘子 | 2KG | NT$2250 |
3 | 草莓 | 1KG | NT$1100 |
4 | 甜瓜 | 6KG | NT$6700 |
首先,是每种水果都只有一个的算法。
#include <stdio.h> #include <stdlib.h> int getMax(int fruitP[], int fruitW[], int form[][9], int fruitNum, int bagW){ int i, j; for(i = 1; i <= fruitNum; i++){ for(j = 1; j <= bagW; j++){ if(j - fruitW[i] < 0){ form[i][j] = form[i - 1][j]; }else if(form[i - 1][j - fruitW[i]] + fruitP[i] > form[i - 1][j]){ form[i][j] = form[i - 1][j - fruitW[i]] + fruitP[i]; }else{ form[i][j] = form[i - 1][j]; } } } } print(int form[][9], int h, int l){ int i, j; for(i = 0; i < l; i++) printf("%.5d ", i); printf("\n"); for(i = 0; i < h; i++){ for(j = 0; j < l; j++){ printf("%.5d ", form[i][j]); } printf("\n"); } } main(){ int fruitP[6] = {0, 450, 570, 225, 110, 670}; int fruitW[6] = {0, 4, 5, 2, 1, 6}; int form[6][9] = {0}; getMax(fruitP, fruitW, form, 5, 8); print(form, 6, 9); }
如果水果是无限个则可以这么写:
#include <stdio.h> #include <stdlib.h> int getMax(int fruitP[], int fruitW[], int form[][9], int fruitNum, int bagW){ int i, j; for(i = 1; i <= fruitNum; i++){ for(j = 1; j <= bagW; j++){ if(j - fruitW[i] < 0){ form[i][j] = form[i - 1][j]; }else if(form[i - 1][j - fruitW[i]] + fruitP[i] > form[i - 1][j]){ if(form[i - 1][j - fruitW[i]] + fruitP[i] > form[i][j - fruitW[i]] + fruitP[i]) form[i][j] = form[i - 1][j - fruitW[i]] + fruitP[i]; else form[i][j] = form[i][j - fruitW[i]] + fruitP[i]; }else{ if(form[i][j - fruitW[i]] + fruitP[i] < form[i - 1][j]) form[i][j] = form[i - 1][j]; else form[i][j] = form[i][j - fruitW[i]] + fruitP[i]; } } } } print(int form[][9], int h, int l){ int i, j; for(i = 0; i < l; i++) printf("%.5d ", i); printf("\n"); for(i = 0; i < h; i++){ for(j = 0; j < l; j++){ printf("%.5d ", form[i][j]); } printf("\n"); } } main(){ int fruitP[6] = {0, 450, 570, 225, 110, 670}; int fruitW[6] = {0, 4, 5, 2, 1, 6}; int form[6][9] = {0}; getMax(fruitP, fruitW, form, 5, 8); print(form, 6, 9); }
一个和无限个的差别在于,在作比较的时候不仅跟上一行比较,还要跟当前行作比较,较大者置换即可。
过程之中的主要问题是一个初始化的问题,之所以5*8个元素需要用到6*9个空间,最主要还是为了理解上以及编写上的方便。
其实有类似的更好的算法,空间上只需一维数组,而且也没不管水果的个数是一个还是无限,只需要在遍历数组的时候改一下方向即可,但是本题作为动态规划入门练习,可能以上面的方法为主会比较好。
动态规划的问题之一是需要大量的空间,所以其实更好的算法的根本目的就是压缩空间。