From 8bb7b9a5107d75c20d0b52756483d74f389179a0 Mon Sep 17 00:00:00 2001 From: Departuers <2644631299@qq.com> Date: Fri, 10 Apr 2020 00:35:42 +0800 Subject: [PATCH] c --- ...\344\274\230\345\206\231\346\263\225.java" | 38 ++++++ .../\344\271\260\344\271\246.java" | 2 +- ...\345\214\205\351\227\256\351\242\230.java" | 3 +- ...\347\232\204\344\273\212\346\230\216.java" | 61 ++++++++++ ...\345\231\250\345\210\206\351\205\215.java" | 79 +++++++++++++ ...\345\220\210\350\203\214\345\214\205.java" | 37 +++++- ...\344\275\223\346\226\271\346\241\210.java" | 36 ++++++ ...\345\270\201\347\263\273\347\273\237.java" | 48 ++++++++ ...\347\256\227\346\226\271\346\241\210.java" | 109 ++++++++++++++++++ 9 files changed, 409 insertions(+), 4 deletions(-) create mode 100644 "ACWing/src/RMQ/ST\350\241\250\346\234\200\344\274\230\345\206\231\346\263\225.java" create mode 100644 "ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\274\200\345\277\203\347\232\204\344\273\212\346\230\216.java" create mode 100644 "ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\234\272\345\231\250\345\210\206\351\205\215.java" create mode 100644 "ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\350\264\247\345\270\201\347\263\273\347\273\237.java" create mode 100644 "ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\351\207\221\346\230\216\347\232\204\351\242\204\347\256\227\346\226\271\346\241\210.java" diff --git "a/ACWing/src/RMQ/ST\350\241\250\346\234\200\344\274\230\345\206\231\346\263\225.java" "b/ACWing/src/RMQ/ST\350\241\250\346\234\200\344\274\230\345\206\231\346\263\225.java" new file mode 100644 index 0000000..cdd4821 --- /dev/null +++ "b/ACWing/src/RMQ/ST\350\241\250\346\234\200\344\274\230\345\206\231\346\263\225.java" @@ -0,0 +1,38 @@ +package RMQ; + +public class ST表最优写法 { + public static void main(String[] args) { + n = 7; + init(); + for (int i = 1; i <= 7; i++) { + System.out.println(query(1, i)); + } + } + + static int n, m; + static int[] log; + static int[][] st; + static int[] arr = {22, 23, 8, 67, 7, 7, 2}; + + static void init() { + log = new int[n + 2]; + log[1] = 0; + for (int i = 2; i <= n + 1; i++) { + log[i] = log[i / 2] + 1; + } + st = new int[n + 2][log[n] + 1]; + for (int i = 1; i <= n; i++) { + st[i][0] = arr[i - 1]; + } + for (int j = 1; 1 << j <= n; j++) { + for (int i = 1; i + (1 << j) - 1 <= n; i++) { + st[i][j] = Math.min(st[i][j - 1], st[i + (1 << j - 1)][j - 1]); + } + } + } + + static int query(int l, int r) { + int k = log[r - l + 1]; + return Math.min(st[l][k], st[r - (1 << k) + 1][k]); + } +} diff --git "a/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\344\271\260\344\271\246.java" "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\344\271\260\344\271\246.java" index 4137c14..38e1c06 100644 --- "a/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\344\271\260\344\271\246.java" +++ "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\344\271\260\344\271\246.java" @@ -14,7 +14,7 @@ package 线性dp.背包模型; * ... * 求取左边的和,加上右边的和 * 左边的方案选择:1~i-1中选择,不包含i的话体积应该是j-k*i - * 则是:f[i-1,j-v[i]*k ] + * 则是:f[i-1,j-v[i]*k] * 最终:f[i,j]=f[i-1,j]+f[i-1,j-v[i]*1]+f[i-1,j-v[i]*2]+...+f[i-1,j-v[i]*k] * 易得f[i,j-v]= f[i-1,j-v[i]*1]+f[i-1,j-v[i]*2]+...+f[i-1,j-v[i]*k] * 可以对应: diff --git "a/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\210\206\347\273\204\350\203\214\345\214\205\351\227\256\351\242\230.java" "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\210\206\347\273\204\350\203\214\345\214\205\351\227\256\351\242\230.java" index 75f8988..0697b30 100644 --- "a/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\210\206\347\273\204\350\203\214\345\214\205\351\227\256\351\242\230.java" +++ "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\210\206\347\273\204\350\203\214\345\214\205\351\227\256\351\242\230.java" @@ -7,12 +7,13 @@ import java.util.Scanner; * 求最大价值 * 转换成01背包问题, * 状态定义为f[i,j]:前i组物品可选,体积不超过j的所有选法最大值 - * 状态划分:选第i组物品的第1个,选第i组物品的第2个,选第i组物品的第s[i]个,,不选第i组物品 + * 状态划分:选第i组物品的第1个,选第i组物品的第2个,选第i组物品的第s[i]个,不选第i组物品 * 状态计算:显然不选第i组物品就是f[i-1,j] * |________|+w[i][1] * |________|+w[i][2] * .... * |________|+w[i][k] + * k代表地i组一共有多少物品 * 前面的最大值如何计算 * 前面的可以取的范围i-1组的物品,要选第i组的第k个物品,就要腾出来这么多 * 那么结合状态定义,最大价值就是:f[i-1,j-v[i][k]]+w[i][k] diff --git "a/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\274\200\345\277\203\347\232\204\344\273\212\346\230\216.java" "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\274\200\345\277\203\347\232\204\344\273\212\346\230\216.java" new file mode 100644 index 0000000..ec4c5f9 --- /dev/null +++ "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\274\200\345\277\203\347\232\204\344\273\212\346\230\216.java" @@ -0,0 +1,61 @@ +package 线性dp.背包模型; + +import java.util.Scanner; + +/** + * 01背包问题 + * 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。 + * 更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。 + * 今天一早金明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的N元。 + * 于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。 + * 他还从因特网上查到了每件物品的价格(都是整数元)。 + * 他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。 + * 设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1,j2,…,jk + * ,则所求的总和为: + * v[j1]∗w[j1]+v[j2]∗w[j2]+…+v[jk]∗w[jk] + * 请你帮助金明设计一个满足要求的购物单。 + * 输入格式 + * 输入文件的第1行,为两个正整数N和m,用一个空格隔开。(其中N表示总钱数,m为希望购买物品的个数) + * 从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有2个非负整数v和p。(其中v表示该物品的价格,p表示该物品的重要度) + * 输出格式 + * 输出文件只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(数据保证结果不超过100000000)。 + * 数据范围 + * 1≤N<30000 + * 1≤m<25, + * 0≤v≤10000, + * 1≤p≤5 + * 输入样例: + * 1000 5 + * 800 2 + * 400 5 + * 300 5 + * 400 3 + * 200 2 + * 输出样例: + * 3900 + */ +public class 开心的今明 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + m = sc.nextInt(); + n = sc.nextInt(); + int e, t; + for (int i = 1; i <= n; i++) { + e = sc.nextInt(); + t = sc.nextInt(); + t *= e; + w[i] = t; + v[i] = e; + } + for (int i = 1; i <= n; i++) { + for (int j = m; j >= v[i]; j--) { + f[j] = Math.max(f[j], f[j - v[i]] + w[i]); + } + } + System.out.println(f[m]); + } + + static int[] f = new int[30010]; + static int[] w = new int[30], v = new int[30]; + static int n, m; +} diff --git "a/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\234\272\345\231\250\345\210\206\351\205\215.java" "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\234\272\345\231\250\345\210\206\351\205\215.java" new file mode 100644 index 0000000..6c4464f --- /dev/null +++ "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\234\272\345\231\250\345\210\206\351\205\215.java" @@ -0,0 +1,79 @@ +package 线性dp.背包模型; + +import java.util.Scanner; + +/** + * 总公司拥有M台 相同 的高效设备,准备分给下属的N个分公司。 + * 各分公司若获得这些设备,可以为国家提供一定的盈利。盈利与分配的设备数量有关。 + * 问:如何分配这M台设备才能使国家得到的盈利最大? + * 求出最大盈利值。 + * 分配原则:每个公司有权获得任意数目的设备,但总台数不超过设备数M。 + * 输入格式 + * 第一行有两个数,第一个数是分公司数N,第二个数是设备台数M; + * 接下来是一个N*M的矩阵,矩阵中的第 i 行第 j 列的整数表示第 i 个公司分配 j 台机器时的盈利。 + * 输出格式 + * 第一行输出最大盈利值; + * 接下N行,每行有2个数,即分公司编号和该分公司获得设备台数。 + * 答案不唯一,输入任意合法方案即可。 + * 数据范围 + * 1≤N≤10, + * 1≤M≤15 + * 输入样例: + * 3 3 + * 30 40 50 + * 20 30 50 + * 20 25 30 + * 输出样例: + * 70 + * 1 1 + * 2 1 + * 3 1 + * 分析: + * 本题相当于AcWing 9 分组背包问题问题。每组物品要么一个不选, + * 要么同一组最多选择其中的一个,本题每个公司可获得的设备数量也是只能选择一个, + * 故状态表示f[i][j]表示在前i家公司中选择分配不超过j台设备的最大盈利。 + * 状态转移方程为f[i][j] = max(f[i-1][j-k]+w[i][k]),其中j >= k。 + * 另外题目要求输出任意一组合法方案,所以用个数组存储方案即可,具体第i组物品选与不选, + * 如果选,选几个,只需要找出其中的一个k,使得f[i][j] == f[i-1][j-k]+w[i][k]即可使得第i个物品选k个是合法的方案。 + */ +public class 机器分配 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + n = sc.nextInt(); + m = sc.nextInt(); + for (int i = 1; i <= n; i++) { + for (int j = 1; j <= m; j++) { + w[i][j] = sc.nextInt(); + } + } + for (int i = 1; i <= n; i++) { + for (int j = 0; j <= m; j++) { + f[i][j] = f[i - 1][j];//一个都不选 + for (int k = 1; k <= j; k++) { + //最多选k个,把k个物品 + f[i][j] = Math.max(f[i][j], f[i - 1][j - k] + w[i][k]); + } + } + } + System.out.println(f[n][m]); + int j = m; + for (int i = n; i != 0; i--) {//倒序往前找决策 + for (int k = 0; k <= j; k++) { + if (f[i][j] == f[i - 1][j - k] + w[i][k]) { + way[i] = k; + j -= k; + break; + } + } + } + for (int i = 1; i <= n; i++) { + System.out.println(i + " " + way[i]); + } + + } + + static int[] way = new int[20]; + static int[][] f = new int[20][20]; + static int n, m; + static int[][] w = new int[20][20]; +} diff --git "a/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\267\267\345\220\210\350\203\214\345\214\205.java" "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\267\267\345\220\210\350\203\214\345\214\205.java" index 3a8f553..00f4360 100644 --- "a/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\267\267\345\220\210\350\203\214\345\214\205.java" +++ "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\267\267\345\220\210\350\203\214\345\214\205.java" @@ -12,16 +12,49 @@ import java.util.Scanner; * 求解将哪些物品装入背包,可使物品体积总和不超过背包容量, * 且价值总和最大。 * 输出最大价值。 + * 状态定义:f[i,j]:只从前i种物品选,且总体积不超过j的选法 + * 属性max:最大价值 + * 状态计算: + * 01背包:f[i,j]=max( f[i-1,j] ,f[i-1][j-v[i]]+w[i]) + * 完全背包:f[i,j]=max(f[i-1,j] ,f[i-1,j-v[i]+w[i] , f[i-1,j-v[i]*2+w[i]*2 ... f[i-1,j-v[i]*k+w[i]*k) + * 易得f[i,j-v]= max(f[i-1,j-v[i]+w[i] , f[i-1,j-v[i]*2+w[i]*2 ... f[i-1,j-v[i]*k+w[i]*k) + * 可以对应: + * 当然可以替换f[i,j]=max( f[i-1,j],f[i,j-v] ) + * 多重背包:f[i,j]=max(f[i-1,j] ,f[i-1,j-v[i]+w[i] , f[i-1,j-v[i]*2+w[i]*2 ... f[i-1,j-v[i]*s[i]+w[i]*s[i]) */ public class 混合背包 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); N = sc.nextInt(); V = sc.nextInt(); - for (int i = 0; i < N; i++) { - + for (int i = 1; i <= N; i++) { + v[i] = sc.nextInt(); + w[i] = sc.nextInt(); + t[i] = sc.nextInt(); + } + for (int i = 1; i <= N; i++) { + if (t[i] == 0) { + for (int j = v[i]; j <= V; j++) { + f[j] = Math.max(f[j], f[j - v[i]] + w[i]); + } + } else { + if (t[i] == -1) t[i] = 1; + for (int k = 1; k <= t[i]; k *= 2) { + for (int j = V; j >= k * v[i]; j--) { + f[j] = Math.max(f[j], f[j - k * v[i]] + w[i] * k); + } + t[i] -= k; + } + if (t[i] > 0) { + for (int j = V; j >= t[i] * v[i]; j--) { + f[j] = Math.max(f[j], f[j - t[i] * v[i]] + w[i] * t[i]); + } + } + } } + System.out.println(f[V]); } + static int[] v = new int[1010], w = new int[1010], t = new int[1010], f = new int[1010]; static int N, V; } diff --git "a/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\350\203\214\345\214\205\351\227\256\351\242\230\346\261\202\345\205\267\344\275\223\346\226\271\346\241\210.java" "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\350\203\214\345\214\205\351\227\256\351\242\230\346\261\202\345\205\267\344\275\223\346\226\271\346\241\210.java" index 0f25666..221d050 100644 --- "a/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\350\203\214\345\214\205\351\227\256\351\242\230\346\261\202\345\205\267\344\275\223\346\226\271\346\241\210.java" +++ "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\350\203\214\345\214\205\351\227\256\351\242\230\346\261\202\345\205\267\344\275\223\346\226\271\346\241\210.java" @@ -2,6 +2,42 @@ package 线性dp.背包模型; import java.util.Scanner; +/** + * 有 N 件物品和一个容量是 V + * 的背包。每件物品只能使用一次。 + * 第 i件物品的体积是 vi,价值是 wi + * 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 + * 输出 字典序最小的方案。这里的字典序是指:所选物品的编号所构成的序列。物品的编号范围是 1…N + * 输入格式 + * 第一行两个整数,N,V + * ,用空格隔开,分别表示物品数量和背包容积。 + * 接下来有 N + * 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i + * 件物品的体积和价值。 + * 输出格式 + * 输出一行,包含若干个用空格隔开的整数,表示最优解中所选物品的编号序列,且该编号序列的字典序最小。 + * 物品编号范围是 1…N + * 数据范围 + * 0f[n,m]边权重为0 + * f[n-1,m-v[i]]+w[i]->f[n,m] 边权重为w[i] + * 要求字典序最小: + * 可能最大价值有多种方案 + * 对于一个物品:有三种情况,必选,可选,不能选 + * 如果物品可选那就一定选则是字典序最小方案 + * 因为是1..n顺序判断的最大价值 + * 要倒序从下面到上面做dp + */ public class 背包问题求具体方案 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); diff --git "a/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\350\264\247\345\270\201\347\263\273\347\273\237.java" "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\350\264\247\345\270\201\347\263\273\347\273\237.java" new file mode 100644 index 0000000..6a19738 --- /dev/null +++ "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\350\264\247\345\270\201\347\263\273\347\273\237.java" @@ -0,0 +1,48 @@ +package 线性dp.背包模型; + +import java.util.Scanner; + +/** + * 给你一个n种面值的货币系统,求组成面值为m的货币有多少种方案。 + * 输入格式 + * 第一行,包含两个整数n和m。 + * 接下来n行,每行包含一个整数,表示一种货币的面值。 + * 输出格式 + * 共一行,包含一个整数,表示方案数。 + * 数据范围 + * n≤15,m≤3000 + * 输入样例: + *

+ * 3 10 + * 1 + * 2 + * 5 + * 输出样例: + * 10 + * 分析: + * 本题与上一题买书问题基本一模一样,只是方案数可能很大,需要用long long来存储。 + * 状态表示:f[i][j]表示用前i种面值的货币组成面值为j的方案数, + * 状态转移方程为f[i][j] = f[i-1][j] + f[i][j-v],边界状态为f[0][0] = 1。 + * 完全背包问题 + */ +public class 货币系统 { + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + n = sc.nextInt(); + m = sc.nextInt(); + for (int i = 1; i <= n; i++) { + v[i] = sc.nextInt(); + } + f[0] = 1; + for (int i = 1; i <= n; i++) { + for (int j = v[i]; j <= m; j++) { + f[j] += f[j - v[i]]; + } + } + System.out.println(f[m]); + } + + static int[] v = new int[20]; + static long[] f = new long[3010]; + static int n, m; +} diff --git "a/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\351\207\221\346\230\216\347\232\204\351\242\204\347\256\227\346\226\271\346\241\210.java" "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\351\207\221\346\230\216\347\232\204\351\242\204\347\256\227\346\226\271\346\241\210.java" new file mode 100644 index 0000000..2039def --- /dev/null +++ "b/ACWing/src/\347\272\277\346\200\247dp/\350\203\214\345\214\205\346\250\241\345\236\213/\351\207\221\346\230\216\347\232\204\351\242\204\347\256\227\346\226\271\346\241\210.java" @@ -0,0 +1,109 @@ +package 线性dp.背包模型; + +import java.util.ArrayList; +import java.util.Scanner; + +/** + * 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。 + * 更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。 + * 今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子: + * 如果要买归类为附件的物品,必须先买该附件所属的主件。 + * 每个主件可以有0个、1个或2个附件。 + * 附件不再有从属于自己的附件。 + * 金明想买的东西很多,肯定会超过妈妈限定的N元。 + * 于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。 + * 他还从因特网上查到了每件物品的价格(都是10元的整数倍)。 + * 他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。 + * 设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1,j2,…,jk,则所求的总和为: + * v[j1]∗w[j1]+v[j2]∗w[j2]+…+v[jk]∗w[jk](其中*为乘号) + * 请你帮助金明设计一个满足要求的购物单。 + * 输入格式 + * 输入文件的第1行,为两个正整数,用一个空格隔开:N m,其中N表示总钱数,m为希望购买物品的个数。 + * 从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有3个非负整数v p q,其中v表示该物品的价格,p表示该物品的重要度(1~5),q表示该物品是主件还是附件。 + * 如果q=0,表示该物品为主件,如果q>0,表示该物品为附件,q是所属主件的编号。 + * 输出格式 + * 输出文件只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<200000)。 + * 数据范围 + * N<32000,m<60,v<10000 + * 输入样例: + * 1000 5 + * 800 2 0 + * 400 5 1 + * 300 5 1 + * 400 3 0 + * 500 2 0 + * 输出样例: + * 2200 + * 分析: + * 本题考察AcWing 9 分组背包问题的应用,分组背包问题是每组物品最多只能选一个, + * 而本题是每组物品可以选任意个,并且组内物品的体积,价值都不同。 + * 简单描述下题意,要买不超过N元钱的物品,物品分主件和附件,每个主件可能有多个附件, + * 要想买附件必须先买其附属的主件,要找出花钱不超过N元买的物品的最大价值, + * 一件物品的价值等于该物品的价格与重要度的乘积。首先考虑属性的存储, + * 主件附件都要考虑物品的价格及价值(价格*重要度),所以可以用个pair存储。 + * 在进行状态转移时,遍历一个主件时考虑买几个附件,设一共有x个附件, + * 则买附件的情况一共有2^x种,可以用状态压缩表示对这x种附件的购买方式,比如有2个附件, + * 10表示只买第二个附件。其它过程与分组背包完全一致,只需要注意价格和价值的累加即可。 + * 分组背包:把每一个主件与附件的组合看成一个组 + * 状态定义:f[i,j]代表前i种主件可选价值不超过j的所有方案 + */ +public class 金明的预算方案 { + static class node { + int v, m; + + public node(int v, int m) { + this.v = v; + this.m = m; + } + } + + public static void main(String[] args) { + Scanner sc = new Scanner(System.in); + m = sc.nextInt(); + n = sc.nextInt(); + int v, p, q; + for (int i = 1; i <= n; i++) { + v = sc.nextInt(); + p = sc.nextInt(); + q = sc.nextInt(); + p *= v; + if (q != 0) { + fu[q].add(new node(v, p)); + } else { + zhu[i] = new node(v, p); + } + } + int t, e; + for (int i = 1; i <= n; i++) { + if (zhu[i] != null) {//是主件 + for (int j = m; j >= 0; j--) { + for (int k = 0; k < 1 << fu[i].size(); k++) {//有哪些附件,二进制枚举所有选和不选的情况 + t = zhu[i].v; + e = zhu[i].m; + for (int u = 0; u < fu[i].size(); u++) { + if ((k >> u & 1) == 1) { + t += fu[i].get(u).v; + e += fu[i].get(u).m; + } + } + if (j >= t) f[j] = Math.max(f[j], f[j - t] + e); + } + } + } + } + System.out.println(f[m]); + + } + + static int[] f = new int[32009]; + static node[] zhu = new node[70]; + static ArrayList[] fu = new ArrayList[70]; + + static { + for (int i = 0; i < fu.length; i++) { + fu[i] = new ArrayList(); + } + } + + static int n, m; +} -- GitLab