用于求解某种最优性质的问题,动态规划与分治法类似。
例题:
0-1 背包问题:有n种物品和一背包,物品i的重量是wi,其价值为vi,其中wi 和 vi均为正整数,背包的容量为w,现需要考虑如何 选择装入背包的物品,使得装入背包中物品的总价值最大?分析一下:
目标函数:从i个物品 累计求和 i个物品 = n 的总价值
约束条件:当 i个物品的重量 <=背包的容量,x 取值 0【不放入】,1 【放入】
分析下这三种情况:
第一种情况:如果 i=0 表示没有放入物体,w=0,表示重量为0 所以为 0
第二种情况: 当 当前物品的重量大于背包总重量 ,当前物体不放入背包
第三种情况,当 当前物品的 重量小于背包总重量,且 判断,如果当前物品放入背包,求当前物品放入背包后的 总价值 或 当前物品不放入背包,求背包可能容纳的总价值,MAX二者取一。
i 物品 \ W 重量 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
1 | 0 | 0 | 0 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 |
2 | 0 | 0 | 0 | 4 | 5 | 5 | 5 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 | 9 |
3 | 0 | 0 | 0 | 4 | 5 | 5 | 5 | 10 | 10 | 10 | 14 | 14 | 14 | 14 | 19 | 19 | 19 | 19 |
4 | 0 | 0 | 0 | 4 | 5 | 5 | 5 | 10 | 11 | 11 | 14 | 15 | 16 | 16 | 19 | 21 | 21 | 21 |
5 | 0 | 0 | 0 | 4 | 5 | 5 | 5 | 10 | 13 | 13 | 14 | 15 | 17 | 18 | 19 | 21 | 23 | 24 |
分析表格:
当重量 w 越来越大时,我们可以判断 物品 i 是否能放入 每一次变化的 递增+1 中,一共递增 17次,因为我们可容纳的重量是17
java 求出最优解:
/**
* @Author wuxiaotian
* @Date 2021/8/26 11:00
* @Version C1.4
*/
public class Test03 {
void OutPutKnapsackDp(int n,int W, int[] weights,int[] values,int[][] c){
int[] x = new int[5]; //n 表示所有的 物品总数
int i = 0;
for ( i = n; i > 0; i--) {
if(W - 1 >= 0) {
if (c[i][W - 1] == c[i - 1][W - 1]) { //重量为w 的最优选择的背包中不包含该物品 判断当前这个物品 放入和不放入价值相等得话 就不放入
x[i - 1] = 0; //不放入该物品
} else {
x[i - 1] = 1; //放入该物品
System.out.println("总总量:" + W + "当前物品重量:" + weights[i] + "剩余重量:" + (W - weights[i]));
W = W - weights[i]; //更新背包目前的最大容量 总容量 - 当前物品容量
}
}
}
if(c[1][W] == 0){ //第一个物品不放入背包
x[0] = 0;
}else{
x[0] = 1; //第一个物品放入背包
}
for (int j = 0; j <n; j++) {
if(x[j] == 1){
System.out.println(String.format("重量为%d: 价值为%d:",weights[j+1],values[j+1]));
}
}
}
public static void main(String[] args) {
Test03 test03 = new Test03();
int n = 4; //物品个数
int W = 17; //总容量
int[] weights = new int[] {3,4,7,8,9};
int[] values = new int[] {4,5,10,11,13};
int [][] c =new int[5][17];
c[0] = new int[] {0 ,0 ,4, 4 ,4 ,4, 4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4, 4};
c[1] = new int[] {0 ,0 ,4, 5, 5, 5, 9, 9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9};
c[2] = new int[] {0, 0, 4, 5, 5, 5, 10, 10, 10, 14, 14, 14, 14, 19, 19, 19, 19};
c[3] = new int[] {0, 0, 4, 5, 5, 5, 10, 11, 11, 14, 15, 16, 16, 19, 21, 21, 21};
c[4] = new int[] {0, 0, 4, 5, 5, 5, 10, 13, 13, 14, 15, 17, 18, 19, 21, 23, 24};
for (int i = 0; i <5; i++) {
for (int j = 0; j < weights.length; j++) {
c[i][j] = j;
}
}
test03.OutPutKnapsackDp(n,W,weights,values,c);
}
}
由于时间原因,以上算法可能不够精简,仅仅实现了功能,小伙伴们有更好的算法可以私聊我,一起学习丫