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

学习动态规划,一开始一头雾水,看了好多博客,写的都是不太适合自己,这篇博客写得通俗易懂https://blog.csdn.net/dapengbusi/article/details/7463968。其实懂了思想,写代码写起来就比较简单了。在这里写一下个人的理解:通过把问题分解为更小规模的问题,分到最小的时候肯定会有一个边界,然后从边界开始反过来求解。有点类似于递归,不过动态规划是用数组或者其他的东西,先把小规模的问题的解存入了数组中,就不用重复计算,提高了效率。详细的讲解还是看参考的博客吧https://blog.csdn.net/dapengbusi/article/details/7463968

 

package backpack;

//0-1背包问题
//给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装
//入背包中物品的总价值最大
//数据:物品个数n=5,物品重量w[n]={2,2,6,5,4},物品价值V[n]={6,3,5,4,6},

public class Package_0_1{
	private int c = 10;             //背包的容量
    private int w[] = {2,2,6,5,4}; //物品的重量
    private int v[] = {6,3,5,4,6}; //物品对应的待加
    private boolean x[] = new boolean[5];  //记录对应的物品有没有装入背包,false表示没有装入
    private int[][] m=new int[5][11];  //状态量,记录最大价值
    
    public Package_0_1() {
    	
    }
    public void getMaxValue() {
    	//从最后一行开始填充二维数组m,从左往右,从底往上
    	int index=w.length-1;  //最后一行
    	for(int j=0;j<=c;j++) {
    		//j代表的是背包的容量,这里从0开始,到最大容量c=10
    		//如果背包的容量j大于物品的重量,则可以把物品放入背包,价值当然就是放入物品的价值
    		if(j>w[index]) {
    			m[index][j]=v[index];
    		}
    		//背包的容量装不下物品,当然价值就是0
    		else {
    			m[index][j]=0;
    		}
    	}
    	//接着在最后一行填充的基础上,从倒数第二行开始,从左往右,从底往上填充价值数组m
    	for(int i=index-1;i>=0;i--) {
    		for(int j=0;j<=c;j++) {
    			//如果放得下物品i,则要考虑放入背包的价值大,还是不放的价值大,取最大值
        		if(j>w[i]) {
        			m[i][j]=m[i+1][j-w[i]]+v[i]>m[i+1][j]?m[i+1][j-w[i]]+v[i]:m[i+1][j];
        		}
        		//如果放不下物品i,则和它的上一次状态相同,也就是它的下一行
        		else {
        			m[i][j]=m[i+1][j];
        		}
    		}
    	}
    	
    	System.out.println("最大价值为:"+m[0][10]);
    	int j=c;
    	for(int i=0;i<w.length-1;i++) {
//    		如果m[i][j]==m[i+1][j],则表示第i件物品没有放入背包
    		if(m[i][j]!=m[i+1][j]) {
    			j=j-w[i];
    			x[i]=true;
    		}   		
    	}
    	//对于最后一件物品,如果m[i][j]不为0,就是放入了背包
    	x[w.length-1]=m[w.length-1][j]==0?false:true;
    	//输出选择的状态,也就是选择了哪几个物品
    	for(int i=0;i<x.length;i++) {
    		if(x[i]) {
    			System.out.println("选择了第 "+i+" 个物品");
    		}
    	}
    }
    
	public static void main(String[] args) {
		Package_0_1 p=new Package_0_1();
		p.getMaxValue();
	}
	
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值