题意整理
- 给定x,y,以及若干数对[ai,bi,ci]。
- 从中选出部分数对,使得ai数对的和不小于x,bi数对的和不小于y,求最小的ci数对的和。
方法一(动态规划)
1.解题思路
- 状态定义:dp[i][j][k]表示选择包装数为i,面包数为j,饮料数为k的情况下,最小的花费。
- 状态初始化:不选择任何包装时,花费为0。
- 状态转移:如果j大于等于breadNum是正常的01背包问题,直接从背包取,如果j小于breadNum,仍然从背包取,只是应该从状态为0的位置转移,对于k的分析也是类似。即
。
2.代码实现
import java.util.*;
public class Solution {
/**
*
* @param breadNum int整型
* @param beverageNum int整型
* @param packageSum int整型二维数组 每个一维数组中有三个数,依次表示这个包装里面的面包数量、饮料数量、花费
* @return int整型
*/
public int minCost (int breadNum, int beverageNum, int[][] packageSum) {
int n=packageSum.length;
/*初始化dp数组,第一维表示当前包装数量,第二维表示面包数,
第三维表示饮料数,整体表示当前最小的花费*/
int[][][] dp=new int[n+1][breadNum+1][beverageNum+1];
for(int i=0;i<=n;i++){
for(int j=0;j<=breadNum;j++){
Arrays.fill(dp[i][j],Integer.MAX_VALUE/2);
}
}
//不选择任何包装时,花费为0
dp[0][0][0]=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=breadNum;j++){
for(int k=0;k<=beverageNum;k++){
//当前费用至少需要前一次费用的数值
dp[i][j][k]=dp[i-1][j][k];
/*如果j大于等于breadNum是正常的01背包问题,直接从背包取
如果j小于breadNum,仍然从背包取,只是应该从状态为0的位置转移
对k这一层的维度也是类似的分析过程*/
dp[i][j][k]=Math.min(dp[i][j][k]
,dp[i-1][Math.max(j-packageSum[i-1][0],0)][Math.max(k-packageSum[i-1][1],0)]
+packageSum[i-1][2]);
}
}
}
return dp[n][breadNum][beverageNum];
}
} 3.复杂度分析
- 时间复杂度:假设输入面包的数目为breadNum,饮料的数目为beverageNum,包装的数量为n,则时间复杂度为
。
- 空间复杂度:需要额外大小为
的dp数组,所以空间复杂度为
。
方法二(空间压缩)
1.解题思路
基本思路和方法一相同,另外可以通过滚动数组的方式降低一维空间的开销,同时为了避免重复计算,需要逆序遍历。
动图展示(测试的输入数据为:2,2,[[1,3,12],[1,2,15],[2,1,20]]):
2.代码实现
import java.util.*;
public class Solution {
/**
*
* @param breadNum int整型
* @param beverageNum int整型
* @param packageSum int整型二维数组 每个一维数组中有三个数,依次表示这个包装里面的面包数量、饮料数量、花费
* @return int整型
*/
static final int INF=Integer.MAX_VALUE/2;
public int minCost (int breadNum, int beverageNum, int[][] packageSum) {
/*初始化dp数组,第一维表示面包数,
第二维表示饮料数,整体表示当前最小的花费*/
int[][] dp=new int[breadNum+1][beverageNum+1];
for(int i=0;i<=breadNum;i++){
Arrays.fill(dp[i],INF);
}
//不选择任何包装时,花费为0
dp[0][0]=0;
int n=packageSum.length;
for(int i=0;i<n;i++){
for(int j=breadNum;j>=0;j--){
for(int k=beverageNum;k>=0;k--){
//通过逆序的方式跟新状态,防止重复计算,同时节省了一维空间
dp[j][k]=Math.min(dp[j][k]
,dp[Math.max(j-packageSum[i][0],0)][Math.max(k-packageSum[i][1],0)]
+packageSum[i][2]);
}
}
}
return dp[breadNum][beverageNum];
}
}3.复杂度分析
- 时间复杂度:假设输入面包的数目为breadNum,饮料的数目为beverageNum,包装的数量为n,则时间复杂度为
。
- 空间复杂度:需要额外大小为
的dp数组,所以空间复杂度为
。

京公网安备 11010502036488号