动态规划——0-1背包问题

背包问题: 给定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];
	}

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值