动态规划——背包问题

文章目录

    • 01背包问题
    • 完全背包问题
    • 01背包和完全背包的小对比
    • 多重背包问题朴素解法
    • 多重背包问题优化解法
    • 分组背包问题

动态规划——背包问题_第1张图片

01背包问题

动态规划——背包问题_第2张图片

动态规划——背包问题_第3张图片

package Chapter5;

import java.util.Scanner;

public class P002 {
	
    static Scanner in = new Scanner(System.in);
    static int N = 1010;
    static int[] v = new int[N];
    static int[] w = new int[N];
    static int[][] f = new int[N][N];
    static int n, m;
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt(); //物品数量
		m = sc.nextInt(); //背包容积
		
        for (int i = 1; i <= n; i++) 
        {
            v[i] = sc.nextInt();
            w[i] = sc.nextInt();
        }
        
        //背包求解
        //f[i][j] 表示前i件物品,体积j的  最大价值
        for(int i=1;i<=n;i++){
        	for(int j=0;j<=m;j++){
        		//case1, 第i个物品不选
        		f[i][j] = f[i-1][j];
        		//如果背包的体积大于第i件物品
        		//case2,必选第i个物品 就是 f[i-1][j-v[i]]+w[i]
        		if(j>=v[i]){
        			f[i][j] = Math.max(f[i][j], f[i-1][j-v[i]]+w[i]);
        		}
        	}
        }
        
        System.out.println(f[n][m]);
		
	}
}

完全背包问题

动态规划——背包问题_第4张图片

优化为2维
动态规划——背包问题_第5张图片

动态规划——背包问题_第6张图片

package Chapter5;
/**
 * 
 * 完全背包问题
 * @author vccyb
 *
 */
import java.io.*;
import java.util.*;
public class P003 {
	static final int N = 1010;
	static int[] v = new int[N]; // 体积
	static int[] w = new int[N]; // 价值
	static int n; //物品数量
	static int m; //背包容积
	static int[][] f = new int[N][N];
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String[] line = br.readLine().split(" ");
		n = Integer.parseInt(line[0]); //物品数量
		m = Integer.parseInt(line[1]); //背包体积
		
		for (int i = 1; i <= n; i++) {
			String[] line2 = br.readLine().split(" ");
            v[i] = Integer.parseInt(line2[0]);
            w[i] = Integer.parseInt(line2[1]);
		 }
		
	   //完全背包问题的解决  三维
		//f[i][j] = f[i-1][j-k*v[i]]+k*w[i]
//		for(int i=1;i<=n;i++){
//			for(int j=0;j<=m;j++){
//				for(int k = 0; k*v[i]<=j;k++){
//					f[i][j] = Math.max(f[i][j], f[i-1][j-k*v[i]]+k*w[i]);
//					System.out.println("前"+i+"个物品,体积小于"+j+"的最大收益为:"+f[i][j]);
//				}
//			}
//		}
		
		
		//完全背包的解决	二维
		//f[i][j] = max(f[i-1][j],f[i][j-v[i]]+w[i])
		for(int i=1;i<=n;i++){
			for(int j=0;j<=m;j++){
				//case1 
				f[i][j] = f[i-1][j];
				//case2 
				if(j>=v[i]){
					f[i][j] = Math.max(f[i][j], f[i][j-v[i]]+w[i]);
				}
			}
		}
		
		//输出结果
		System.out.println(f[n][m]);
	}
}

01背包和完全背包的小对比

动态规划——背包问题_第7张图片

多重背包问题朴素解法

多重背包问题:
物品多个,但不是无限个
k 动态规划——背包问题_第8张图片

package Chapter5;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class P004 {
	static final int N = 110;
	static int[] v = new int[N]; //物品体积
	static int[] w = new int[N]; //物品价值
	static int[] s = new int[N]; //物品数量
	static int n; //物品种类数量
	static int m; //背包的容积
	static int[][] f = new int[N][N];
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		String[] line1 = br.readLine().split(" ");
		n = Integer.parseInt(line1[0]);
		m = Integer.parseInt(line1[1]);
		
		for(int i=1;i<=n;i++){
			String[] line2 = br.readLine().split(" ");
			v[i] = Integer.parseInt(line2[0]);
			w[i] = Integer.parseInt(line2[1]);
			s[i] = Integer.parseInt(line2[2]);
		}
		
		//输入完毕
		for(int i=1;i<=n;i++){
			for(int j=0;j<=m;j++){
				for(int k=0;k<=s[i]&&k*v[i]<=j;k++){
					f[i][j] = Math.max(f[i][j], f[i-1][j-v[i]*k]+w[i]*k);
				}
			}
		}
		
		System.out.println(f[n][m]);
		
		
	}

}

多重背包问题优化解法

考虑:怎么把多重背包问题化为01背包问题

v,w,s 拆分
v,w
v,w

v,w (重复s次)
就转化为了01背包问题

问题:拆法是很笨的 比如 每个物品有2000个,有2000种类物品。。。
时间复杂度也很高

二进制拆法
动态规划——背包问题_第9张图片

动态规划——背包问题_第10张图片

分组背包问题

动态规划——背包问题_第11张图片

package Chapter5;

import java.util.Scanner;

/**
 * 分组背包问题
 * @author vccyb
 *
 */
public class P009 {
	static final int N = 110;
	static int[][] w = new int[N][N]; //物品价值
	static int[][] v = new int[N][N]; //物品体积
	static int[] s = new int[N]; //每一组的个数
	static int[][] f = new int[N][N]; 

	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt(); //物品组数
		int m = sc.nextInt(); //背包容量
        for(int i = 1;i <= n;i++)
        {
            s[i] = sc.nextInt();
            for(int j = 1;j <= s[i];j++)
            {
                v[i][j] = sc.nextInt();
                w[i][j] = sc.nextInt();
            }
        }
		
		
		//分组背包求解
        for(int i = 1;i <= n;i++)
            for(int j = 0;j <= m;j ++)
            {
                f[i][j] = f[i - 1][j];//一个都不选时
                for(int k = 1;k <= s[i];k++)//选第k个,k=0时v[i][k]为0
                {
                    if(v[i][k] <= j)
                        f[i][j] = Math.max(f[i][j], f[i - 1][j - v[i][k]] + w[i][k]);
                }
            }

		
		System.out.println(f[n][m]);
	}
	
}

你可能感兴趣的:(算法学习)