题目一
题目描述
在n个物品中挑选若干物品装入背包,最多能装多满?假设背包的大小为m,每个物品的大小为Ai
样例
输入:
数组 = [3,4,8,5]
backpack size = 10
输出:
9
解释:
装4和5
题解
fi表示前i个物品选一些物品放入容量为j的背包中能否放满。
public class Solution {
/**
* @param m: An integer m denotes the size of a backpack
* @param A: Given n items with size A[i]
* @return: The maximum size
*/
public int backPack(int m, int[] A) {
boolean f[][] = new boolean[A.length + 1][m + 1];
for (int i = 0; i <= A.length; i++) {
for (int j = 0; j <= m; j++) {
f[i][j] = false;
}
}
f[0][0] = true;
for (int i = 1; i <= A.length; i++) {
for (int j = 0; j <= m; j++) {
f[i][j] = f[i - 1][j];
if (j >= A[i-1] && f[i-1][j - A[i-1]]) {
f[i][j] = true;
}
} // for j
} // for i
for (int i = m; i >= 0; i--) {
if (f[A.length][i]) {
return i;
}
}
return 0;
}
}
题目二
题目描述
有 n 个物品和一个大小为 m 的背包. 给定数组 A 表示每个物品的大小和数组 V 表示每个物品的价值.
样例
输入:
m = 10
A = [2, 3, 5, 7]
V = [1, 5, 2, 4]
输出:
9
解释:
装入 A[1] 和 A[3] 可以得到最大价值, V[1] + V[3] = 9
题解
设定 fi 表示前 i 个物品装入大小为 j 的背包里, 可以获取的最大价值总和. 决策就是第i个物品装不装入背包, 所以状态转移方程就是
f[i][j] = max(f[i - 1][j], f[i - 1][j - A[i]] + V[i])
public class Solution {
/**
* @param m: An integer m denotes the size of a backpack
* @param A & V: Given n items with size A[i] and value V[i]
* @return: The maximum value
*/
public int backPackII(int m, int[] A, int V[]) {
// write your code here
int[][] dp = new int[A.length + 1][m + 1];
for (int i = 0; i <= A.length; i++) {
for (int j = 0; j <= m; j++) {
if (i == 0 || j == 0) {
dp[i][j] = 0;
} else if (A[i - 1] > j) {
dp[i][j] = dp[(i - 1)][j];
} else {
dp[i][j] = Math.max(dp[(i - 1)][j], dp[(i - 1)][j - A[i - 1]] + V[i - 1]);
}
}
}
return dp[A.length][m];
}
}
题目三
题目描述
给出 n 个物品, 以及一个数组,
nums[i]
代表第i
个物品的大小, 保证大小均为正数并且没有重复, 正整数target
表示背包的大小, 找到能填满背包的方案数。
每一个物品可以使用无数次
样例
输入:
nums = [2,3,4,5] 和 target = 7
输出:
3
解释:
方案有:
[2, 5]
[3, 4]
[2, 2, 3]
题解
fi表示只考虑前i件物品,取到物品重量和为j的方法数量,这题和完全背包做法类似
public class Solution {
/**
* @param nums an integer array and all positive numbers, no duplicates
* @param target an integer
* @return an integer
*/
public int backPackIV(int[] nums, int target) {
// Write your code here
int m = target;
int []A = nums;
int f[][] = new int[A.length + 1][m + 1];
f[0][0] = 1;
for (int i = 1; i <= A.length; i++) {
for (int j = 0; j <= m; j++) {
int k = 0;
while(k * A[i-1] <= j) {
f[i][j] += f[i-1][j-A[i-1]*k];
k+=1;
}
} // for j
} // for i
return f[A.length][target];
}
}
题目四
题目描述
给你一个
整数数组 coins
,表示不同面额的硬币;以及一个整数amount
,表示总金额。计算并返回可以凑成总金额所需的
最少的硬币个数
。如果没有任何一种硬币组合能组成总金额,返回 -1 。你可以认为
每种硬币的数量是无限的
。
样例
输入:
coins = [1, 2, 5], amount = 11
输出:
3
解释:
11 = 5 + 5 + 1
题解
public class Solution {
public int coinChange(int[] coins, int amount) {
int max = amount + 1;
int[] dp = new int[amount + 1];
Arrays.fill(dp, max);
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
for (int j = 0; j < coins.length; j++) {
if (coins[j] <= i) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
}