背包问题汇总-java

一、01背包

内容:有n件物品和容量为m的背包 给出i件物品的重量以及价值 求解让装入背包的物品重量不超过背包容量 且价值最大 

特点:每个物品只有一件供你选择放还是不放

1. 二维解法 

    设f[i][j]表示前i件物品 总重量不超过j的最大价值 可得出状态转移方程 :

        f[i][j]=max{f[i-1][j-w[i]]+v[i],f[i-1][j]} 

    w[i]:重量数组,v[i]:价值数组

    代码如下:

// 0,1背包:二维法
	public static int bag1(int W, int[] w, int[] v) {
		int n = w.length - 1;// 第一个值,不算
		int[][] f = new int[n + 1][W + 1];
		for (int i = 1; i <= n; i++)
			for (int j = W; j > 0; j--) {
				if (w[i] <= j)
					f[i][j] = Math.max(f[i - 1][j], f[i - 1][j - w[i]] + v[i]);
				else
					f[i][j] = f[i - 1][j];
			}
		return f[n][W]; // 最优解
	}

    缺点:数据大时,无法处理。

2.一维解法 

    用一维数组代替二维数组就解决了二维数组的问题

    设f[j]表示重量不超过j公斤的最大价值 可得出状态转移方程 :

        f[j]=max{f[j],f[j−w[i]]+v[i]}

    代码如下:

// 0,1背包:一维法
	public static int bag2(int W, int[] w, int[] v) {
		int n = w.length - 1;// 第一个值,不算
		int[] f = new int[W + 1];
		for (int i = 1; i <= n; i++)
			for (int j = W; j >= w[i]; j--)
				if (f[j - w[i]] + v[i] > f[j])
					f[j] = f[j - w[i]] + v[i];
		return f[W]; // 最优解
	}

二、完全背包

内容:有n件物品和容量为m的背包 给出i件物品的重量以及价值 求解让装入背包的物品重量不超过背包容量 且价值最大 

特点: 每个物品可以无限选用

    有二维和一维两种,但二维的有一定局限 所以只介绍一维方法 

    设f[j]表示重量不超过j公斤的最大价值 可得出状态转移方程 :

        f[j]=max{f[j],f[j−w[i]]+v[i]}

    区别:0,1背包是从大到小遍历,完全背包是从小到大遍历

    代码如下:

// 完全背包:一维法
	public static int bag3(int W, int[] w, int[] v) {
		int n = w.length - 1;// 第一个值,不算
		int[] f = new int[W + 1];
		for (int i = 1; i <= n; i++)
			for (int j = w[i]; j <= W; j++)
				if (f[j - w[i]] + v[i] > f[j])
					f[j] = f[j - w[i]] + v[i];
		return f[W]; // 最优解
	}

三、多重背包

内容:有n件物品和容量为m的背包 给出i件物品的重量以及价值 还有数量 求解让装入背包的物品重量不超过背包容量 且价值最大 

特点:每个物品都有了一定的数量

    设f[j]表示重量不超过j公斤的最大价值 可得出状态转移方程 : 

    f[j]=max{f[j],f[j−k∗w[i]]+k∗v[i]}

    代码如下:

// 多重背包:一维法
	public static int bag4(int W, int[] w, int[] v, int[] num) {
		int n = w.length - 1;// 第一个值,不算
		int[] f = new int[W + 1];
		for (int i = 1; i <= n; i++)
			for (int j = W; j >= w[i]; j--)
				for (int k = 0; k <= num[i] && j - k * w[i] >= 0; k++) {
					if (f[j - k * w[i]] + k * v[i] > f[j])
						f[j] = f[j - k * w[i]] + k * v[i];
				}

		return f[W]; // 最优解
	}

四、背包问题应用在,数组中找固定和的问题

 
查找和为100的所有组合


    public static void dfs(int current, int sum, int[] questions, ArrayList<Integer> path,
            HashSet<List<Integer>> result) {
        if (sum == 100) {
            result.add(new ArrayList<>(path));
            return;
        }
        if (sum > 100) {
            return;
        }
        for (int i = current; i < questions.length; i++) {
            path.add(questions[i]);
            dfs(i + 1, sum + questions[i], questions, path, result);
            path.remove(path.size() - 1);
        }
    }
 
 
  

 判断是否有和为100的组合

 public static boolean findSum100(int[] a) {
        boolean[] dp = new boolean[101];
        dp[a[0]] = true;
        for (int i = 1; i < a.length; i++) {
            for (int j = 100; j >= a[i]; j--) {
                if (dp[j - a[i]]) {
                    dp[j] = true;
                }
            }
            if (dp[100]) {
                return true;
            }
        }
        return false;
    }

猜你喜欢

转载自blog.csdn.net/qq_19446965/article/details/81349807
今日推荐