zoukankan      html  css  js  c++  java
  • 动态规划-背包问题

    1、0/1背包问题:在N件物品取出若干件放在容量为W的背包里,每件物品的体积为W1,W2……Wn(Wi为整数),与之相对应的价值为P1,P2……Pn(Pi为整数)。求背包能够容纳的最大价值。

    递推公式:F(i, j) = Max{ F(i-1, j)+ F(i-1, j-wi)+pi  }

    原理分析:考虑第i件物品,假设不加入,最大值则为放入i-1件时的最大值;假设加入,最大值则为当前值+剩余空间的最大值,最终两者情况相比取其大。子问题也遵循相同的原理。

    2、代码实现:

      (1)递归实现:

       

    import java.util.Scanner;
    
    /**
     * 
     * @author 
     * 0/1背包问题
     */
    public class Main9 {
    	public static void main(String args[]) {
    		Scanner s = new Scanner(System.in);
    		/**
    		 * 定义测试数据
    		 */
    		int w[] = {1,5,2,3,4};
    		int v[] = {5,7,2,6,100};
    		int len = w.length;
    		int topW = 8;
    		int topV = findMaxVal(w,v,len-1,topW);
    		System.out.println(topV);
    		s.close();
    		
    	}
    	public static int findMaxVal(int[] w,int[] v,int cur_index,int cur_topw) {
    		/*
    		 * 递归结束条件:没有物品可取
    		 */
    		if(cur_index<0) {
    			return 0;
    		}
    		
    		//假设不取第i件物品
    		int lastMax = findMaxVal(w, v,cur_index-1, cur_topw);
    		int curMax = lastMax;
    		if(w[cur_index]<=cur_topw) {
    			//假设取第i件物品
    			curMax = Math.max(lastMax, findMaxVal(w,v,cur_index-1,(cur_topw-w[cur_index]))+v[cur_index]);
    		}
    		return curMax;
    	}
    }
    

      (2)递归遍历+记忆搜索:当第一次计算时记录值。缩小遍历次数。

    import java.util.Scanner;
    
    public class Main9_2 {
    	public static void main(String args[]) {
    		Scanner s = new Scanner(System.in);
    		/**
    		 * 定义测试数据
    		 */
    		int w[] = {1,5,2,3,4};
    		int v[] = {5,7,2,6,1};
    		int len = w.length;
    		int topW = 8;
    		int keep[][] = new int[len][topW+1];
    		//先将记录数组初始化为-1.
    		for(int i=0;i<len;i++) {
    			for(int j=0;j<=topW;j++) {
    				keep[i][j] = -1;
    			}
    		}
    		int topV = findMaxVal(w,v,len-1,topW,keep);
    		System.out.println(topV);
    		s.close();
    		
    	}
    	public static int findMaxVal(int[] w,int[] v,int cur_index,int cur_topw,int keep[][]) {
    		/*
    		 * 递归结束条件:选择到最后一件物品
    		 */
    		if(cur_index==0) {
    			int res = w[0]<=cur_topw?v[0]:0;
    			return res;
    		}
    		//假设不取第i件物品,查询子问题是否被记录
    		int lastMax= keep[cur_index-1][cur_topw]==-1?
    				findMaxVal(w, v,cur_index-1, cur_topw,keep):keep[cur_index-1][cur_topw];
    		
    		int curMax = lastMax;
    		if(w[cur_index]<=cur_topw) {
    			//假设取第i件物品,递归之前查询是否被记录。
    			int temp = keep[cur_index-1][cur_topw-w[cur_index]]==-1?findMaxVal(w,v,cur_index-1,(cur_topw-w[cur_index]),keep):
    				keep[cur_index-1][cur_topw-w[cur_index]];
    			curMax = Math.max(lastMax,temp+v[cur_index]);
    		}
    		return curMax;
    	}
    }
    

      (3)多重循环实现:使用二维数组记录结果

    import java.util.Scanner;
    
    public class Main9_3 {
    	public static void main(String args[]) {
    		Scanner s = new Scanner(System.in);
    		//定义测试数据
    		int w[] = {1,5,2,3,4};
    		int v[] = {5,7,2,6,1};
    		int len = w.length;
    		int topW = 8;
    		int keep[][] = new int[len][topW+1];
    		for(int i=0;i<=topW;i++) {
    			keep[0][i] = w[0]<=i?v[0]:0;
    		}
    		//开始填表(二维数组)
    		for(int i=1;i<len;i++) {
    			for(int j=0;j<=topW;j++) {
    				keep[i][j] = keep[i-1][j];
    				if(w[i]<=j) {
    					keep[i][j] = Math.max(keep[i][j], keep[i-1][j-w[i]]+v[i]);
    				}
    			}
    		}
    		//打印填表结果,实际可省略
    		for(int i=0;i<len;i++) {
    			for(int j=0;j<=topW;j++) {
    				System.out.print(keep[i][j]+" ");
    			}
    			System.out.println();
    		}
    		System.out.println(keep[len-1][topW]);
    		s.close();
    	}
    
    }
    

      (4)多重循环实现:使用一维循环数组记录当前结果。

        》要点:记录当前值时,需要从后往前更新(这也是循环的体现)。

     

    package yrc1;
    
    import java.util.Scanner;
    
    public class Main9_4 {
    	public static void main(String args[]) {
    		//最后结果:0 5 5 7 11 11 13 13 14 
    		Scanner s = new Scanner(System.in);
    		//定义测试数据
    		int w[] = {1,5,2,3,4};
    		int v[] = {5,7,2,6,1};
    		int len = w.length;
    		int topW = 8;
    		int keep[] = new int[topW+1];
    		for(int i=0;i<=topW;i++) {
    			keep[i] = w[0]<=i?v[0]:0;
    		}
    		for(int i=1;i<len;i++) {
    			for(int j=topW;j>=w[i];j--) {
    				keep[j] = Math.max(keep[j], keep[j-w[i]]+v[i]);
    			}
    		}
    		//显示最后记录结果
    		for(int i=0;i<=topW;i++) {
    			System.out.print(keep[i]+" ");
    		}
    		System.out.println("
    "+keep[topW]);
    	}
    
    }
    

      

      

      

  • 相关阅读:
    【华为敏捷/DevOps实践】6.架构师在新兴的DevOps组织应该扮演什么样的角色?
    【华为敏捷/DevOps实践】7. 敏捷,DevOps,傻傻不分清楚
    【华为敏捷/DevOps实践】8. 持续交付,持续部署,傻傻分不清楚
    【华为云动态】华为云开放日发布云专家激励计划,要将开发者“宠”上天
    【华为敏捷/DevOps实践】5. 如何避免DevOps变革的六大“焦油坑”
    【官方活动】亲,咱简历上的精通‘微服务’您真的懂吗? 奉送21天实战微服务免费课程
    00026_方法
    富文本编辑器umeditor支持从word复制粘贴保留格式和图片的插件
    富文本编辑器ueditor支持从word复制粘贴保留格式和图片的插件
    富文本编辑器tinymce支持从word复制粘贴保留格式和图片的插件
  • 原文地址:https://www.cnblogs.com/dream-flying/p/12567109.html
Copyright © 2011-2022 走看看