这道题重在思路,也是典型的0 1 背包问题,是背包问题的升级版
主件携带附件,在Java中很容易就想到了map结构,key是主件的id值,value是附件
当key为0时候,里面就全是主件了
同时考虑状态转移方程,考虑的情况,一共有4种
1、买主件 + 两个附件
2、买主件 + 一个附件
3、只买主件
4、什么都不买
考虑好之后可以直接上代码了,因为人是弱鸡,只会二维背包动态,代码如下
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.*;
/**
* @Author congge
* @Date 2023/10/1 21:03
* @description 金明的预算方案
* https://www.luogu.com.cn/problem/P1064
*/
public class Main {
public static void main(String[] args) {
Input scan = new Input();
int n = scan.nextInt() / 10;
int m = scan.nextInt();
/**
* 保留所有主键以及附件
* father 为 0 的都存到了0号位当中
*/
HashMap<Integer, ArrayList<Good>> sonAndFather = new HashMap<>();
/**
* 初始化map
*/
for (int i = 0; i <= m; i++) {
sonAndFather.put(i, new ArrayList<>());
}
/**
* 键入
*/
for (int i = 1; i <= m; i++) {
Good good = new Good();
good.v = scan.nextInt() / 10;
good.p = scan.nextInt() * good.v;
good.father = scan.nextInt();
good.idx = i;
sonAndFather.get(good.father).add(good);
}
ArrayList<Good> fathers = sonAndFather.get(0);
int M = fathers.size();
/**
* 这里只需要dp一下主键即可,附件附加到主键上面判断就好
*/
int[][] dp = new int[M][n + 1];
Good father = fathers.get(0);
ArrayList<Good> sonOfFather = sonAndFather.get(father.idx);
/**
* 表示当前主键的孩子数目
*/
int sonOfSize = sonOfFather.size();
/**
* 用于计算两个孩子的时候总的钱与价值
*/
int sumV;
int sumP;
/**
* 用于计算一个孩子的时候的钱与价值
*/
int curSumV;
int curSumP;
/**
* 初始化边界
*/
for (int j = father.v; j <= n; j++) {
/**
* 带两个附件的
*/
if (sonOfSize == 2) {
sumV = father.v + sonOfFather.get(0).v + sonOfFather.get(1).v;
/**
* 钱大于总共的钱的时候计算
*/
if (j >= sumV) {
sumP = father.p + sonOfFather.get(0).p + sonOfFather.get(1).p;
dp[0][j] = sumP;
continue;
}
}
/**
* 带一个附件的
*/
if (sonOfSize >= 1) {
for (int k = 0; k < sonOfSize; k++) {
curSumV = sonOfFather.get(k).v + father.v;
/**
* 这里同理
*/
if (j >= curSumV) {
curSumP = sonOfFather.get(k).p + father.p;
dp[0][j] = Math.max(dp[0][j], curSumP);
}
}
}
/**
* 只有主件的情况
*/
sumV = father.v;
if (j >= sumV) {
sumP = father.p;
dp[0][j] = Math.max(dp[0][j], sumP);
}
}
for (int i = 1; i < M; i++) {
father = fathers.get(i);
sonOfFather = sonAndFather.get(father.idx);
sonOfSize = sonOfFather.size();
for (int j = 1; j <= n; j++) {
/**
* 带两个附件的
*/
if (sonOfSize == 2) {
sumV = father.v + sonOfFather.get(0).v + sonOfFather.get(1).v;
if (j >= sumV) {
sumP = father.p + sonOfFather.get(0).p + sonOfFather.get(1).p;
dp[i][j] = dp[i - 1][j - sumV] + sumP;
}
}
/**
* 带一个附件的
*/
if (sonOfSize >= 1) {
for (int k = 0; k < sonOfSize; k++) {
curSumV = sonOfFather.get(k).v + father.v;
if (j >= curSumV) {
curSumP = sonOfFather.get(k).p + father.p;
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - curSumV] + curSumP);
}
}
}
/**
* 只有主件的情况
*/
if (j >= father.v) {
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - father.v] + father.p);
}
/**
* 什么都不买的时候
*/
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j]);
}
}
System.out.println(dp[M - 1][n] * 10);
}
static class Good {
int v;
int p;
int idx;
int father;
}
static class Input {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
public int nextInt() {
try {
in.nextToken();
} catch (IOException e) {
e.printStackTrace();
}
return (int) in.nval;
}
}
}