背包问题: 给定n种物品和一个书包。物品I的体积是wi,其价值为vi,背包的容量为c。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?在装入背包时,每种物品i只有两种选择:装入或者不装入。既不能装入多次,也不能只装入一部分 .
物品类:
public class Goods {
// 体积
int volume;
// 价值
int values;
public Goods(int vol, int value) {
this.volume = vol;
this.values = value;
}
}
一、暴力求解
/**
* @param c
* @param goods
*/
public void solveByForce(int c, Goods[] goods) {
// 循环内保存背包当前配置
int[] currGoods = new int[goods.length];
// 最终背包中价值最大的情况
int[] bestGoods = new int[goods.length];
// 最终背包类物品数量
int finalNubmber = 0;
// 最佳总价值
int bestValue = 0;
for (int i = 0; i < goods.length; i++) {
int w = c - goods[i].volume;
int v = goods[i].values;
int index = 0;
currGoods[index] = i;
for (int j = 0; j < goods.length; j++) {
if (j !=i && goods[j].volume <= w) {
index++;
currGoods[index] = j;
w = w - goods[j].volume;
v = v + goods[j].values;
} else {
continue;
}
}
if (bestValue < v) {
bestValue = v;
finalNubmber = index;
for (int m = 0; m <= finalNubmber; m ++) {
bestGoods[m] = currGoods[m];
}
} else {
continue;
}
}
System.out.println("bestValue = " + bestValue);
for(int i = 0; i <= finalNubmber; i++) {
System.out.print(bestGoods[i] + " ");
}
}
二、动态规划方式求解:
令dp[i][j] 表示将前i个物品放入容量为j的背包得到的最大值,那么就有两种情况:
1.第i个物品能放入背包 也就是说 第i个物品的体积 wi <= j 那么dp[i][j] = dp[i - 1][j - wi] + vi(第i个物品的价值 )
2.第i个物品放不进去了 也就是说 wi > j 那么就是只能放前i - 1 个物品了 dp[i][j] = dp[i -1][j]
故状态转移方程为dp[i][j] = max(dp[i - 1][j - wi] + vi,dp[i -1][j]) ;
public int sloveByDp(int c, Goods[] goods) {
int w = c;
int[][] dp = new int[goods.length][c + 1];
for (int i = 0; i < goods.length; i++) {
for (int j = c; j >= 0; j--) {
if (i - 1 >= 0) {
if (j < goods[i].volume) {
dp[i][j] = dp[i - 1][j];
} else {
dp[i][j] = Math.max(dp[i - 1][j]
, dp[i - 1][j - goods[i].volume]
+ goods[i].values);
}
} else {
// 第0个放入
if (j - goods[i].volume >= 0) {
dp[i][j] = goods[i].values;
}
}
}
}
return dp[goods.length - 1][c];
}