代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @author 1329540850@qq.com
* @version V2.1
* @date 2019/8/14 11:10
* @since 2.1.0
*/
public class Main {
public static void main(String[] args) {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
try {
String[] input = bufferedReader.readLine().split("\\s+");
int money = Integer.valueOf(input[0]);
int itemNum = Integer.valueOf(input[1]);
// 价格
int[] prices = new int[itemNum];
// 价值 = 价格*重要度
int[] values = new int[itemNum];
// 类型。=0表示主件,>0表示附件,数值为所属的主件,编号从1开始。
int[] types = new int[itemNum];
for (int i = 0; i < itemNum; i++) {
input = bufferedReader.readLine().split("\\s+");
prices[i] = Integer.valueOf(input[0]);
values[i] = prices[i] * Integer.valueOf(input[1]);
types[i] = Integer.valueOf(input[2]);
}
// 1.对每一个主件及其所属附件进行01背包。将问题转为分组问题。
int[][] dps = new int[itemNum][money+1];
for (int i = 0; i < itemNum; i++) {
// 当类型为主件时,对当前主件及其所属附件进行01背包,注意必须选择主件。
if (types[i] == 0) {
// 记录,对当前主件进行01背包
int masterNo = i + 1;
// 为所有背包加入主件
for (int sum=money; sum >= prices[i]; sum--) {
dps[i][sum] = values[i];
}
for (int j = 0; j < itemNum; j++) {
// 类型为附件,主件已经提前加入
if (types[j] == masterNo) {
// 状态转移方程, 注意这里使用一维数组优化, 所以为倒序。
for(int sum=money; sum>= (prices[j]+ prices[i]); sum--) {
// F[v] = MAX(F(v), F(v-C) + W)
dps[i][sum] = Math.max(dps[i][sum], dps[i][sum - prices[j]] + values[j]);
}
}
}
}
}
// 2. 进行分组背包
int[] dp = new int[money+1];
// 遍历分组
for(int i=0; i<itemNum; i++) {
// 只需要主件分组
if (types[i] == 0) {
// 遍历容量, 因为使用一维数组优化,采用倒序遍历
for (int v = money; v >= 0; v--) {
// 遍历组件中的每件物品
for (int k = 0; k <= money; k++) {
if (v-k >= 0) {
dp[v] = Math.max(dp[v], dp[v - k] + dps[i][k]);
}
}
}
}
}
System.out.println(dp[money]);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
原文:https://www.cnblogs.com/bosslv/p/11388925.html