前言
背包问题入门级难度:
问题:
思路:
解这类背包问题时,需要建立一个二位数组,用这个二维数组来记录每个子容量能存储的最大价值。我们要做的就是填这个数组,然后把最后一个元素(最大价值)返回。
设物品体积数组为cap[],价值数组为val[]
状态转移方程:
f( i )( j ) = max{ f( i-1 )( j ) , f( i-1 )( j-cap[i] ) + v[i] }
代码:
代码中输出了我们分析时要填的二维数组。
public class Problem04 {
public static void main(String[] args) {
Map<Integer, Integer> map = new LinkedHashMap<>();
map.put(2, 3);
map.put(3, 4);
map.put(4, 5);
map.put(5, 6);
System.out.print("背包可容纳最大价值:" + getMaxValue(map, 8));
}
private static Integer getMaxValue(Map<Integer, Integer> gems, int capacity) {
int[][] maxValue = new int[gems.size() + 1][capacity + 1];
List<Integer> gemList = new ArrayList<>();
int choose, notChoose;
for (int i = 0; i < gems.size() + 1; i++) {
maxValue[i][0] = 0;
}
for (int i = 0; i < capacity + 1; i++) {
maxValue[0][i] = 0;
}
gemList.add(0);
for (Integer gemKey : gems.keySet()) {
gemList.add(gemKey);
}
for (int i = 1; i < gems.size() + 1; i++) {
for (int j = 1; j < capacity + 1; j++) {
if (gemList.get(i) > j) {
maxValue[i][j] = maxValue[i - 1][j];
} else {
choose = gems.get(gemList.get(i)) + maxValue[i - 1][j - gemList.get(i)];
notChoose = maxValue[i - 1][j];
maxValue[i][j] = Math.max(choose, notChoose);
}
}
}
for (int i = 0; i < gems.size() + 1; i++) {
for (int j = 0; j < capacity + 1; j++) {
System.out.print(maxValue[i][j] + " ");
}
System.out.println();
}
getDetails(maxValue, gems, gemList, gems.size() + 1, capacity + 1);
return maxValue[gems.size()][capacity];
}
private static void getDetails(int[][] maxValue, Map<Integer, Integer> gems, List<Integer> gemList, int rows, int cols) {
List<Integer> details = new ArrayList<>();
while (rows > 1 && cols > 1) {
if (maxValue[rows - 1][cols - 1] != maxValue[rows - 2][cols - 1]) {
details.add(rows - 1);
rows--;
cols = cols - 1 - gemList.get(rows - 1);
} else {
rows--;
}
}
System.out.println("装入背包的有:");
for (int i = 0; i < details.size(); i++) {
System.out.println("体积为"+gemList.get(details.get(i))+",价值为"+gems.get(gemList.get(details.get(i)))+"的石头");
}
}
}