diff --git "a/ACWing/src/dp/\346\240\221\345\275\242dp/\346\234\211\344\276\235\350\265\226\347\232\204\350\203\214\345\214\205\351\227\256\351\242\230.java" "b/ACWing/src/dp/\346\240\221\345\275\242dp/\346\234\211\344\276\235\350\265\226\347\232\204\350\203\214\345\214\205\351\227\256\351\242\230.java" index 6549d311f540a2d95111f776dfad959ef58db695..8b98f58f37d05c68673723635d83740086e115f4 100644 --- "a/ACWing/src/dp/\346\240\221\345\275\242dp/\346\234\211\344\276\235\350\265\226\347\232\204\350\203\214\345\214\205\351\227\256\351\242\230.java" +++ "b/ACWing/src/dp/\346\240\221\345\275\242dp/\346\234\211\344\276\235\350\265\226\347\232\204\350\203\214\345\214\205\351\227\256\351\242\230.java" @@ -3,20 +3,7 @@ package dp.树形dp; import java.util.Scanner; /** - * 有n个物品和容量为V的背包 - * 物品之间有依赖关系,关系组成一颗树的形状, - * 如果要选一个物品,则必选他的父节点 - * 求最大价值 - * dfs+dp dp.树形dp - * 状态定义:集合f[u,j]:所有从以u为根的子树中选,且总体积不超过j的选法 - * 属性:max最大价值 - * 集合划分:子树1,子树3,子树3 - * 再根据体积划分子树:体积是0-m 有m+1总可能 - * 用一个数字表示一类方案 - * 把每一颗子树看做物品组,分组背包问题 - * 链式前向星建图 - * 有 N 个物品和一个容量是 V - * 的背包。 + * 有 N 个物品和一个容量是 V的背包。 * 物品之间具有依赖关系,且依赖关系组成一棵树的形状。如果选择一个物品,则必须选择它的父节点。 * 如下图所示: * 如果选择物品5,则必须选择物品1和2。这是因为2是5的父节点,1是2的父节点。 @@ -49,6 +36,20 @@ import java.util.Scanner; * 3 6 2 * 输出样例: * 11 + *
+ * 有n个物品和容量为V的背包 + * 物品之间有依赖关系,关系组成一颗树的形状, + * 如果要选一个物品,则必选他的父节点 + * 求最大价值 + * dfs+dp dp.树形dp + * 状态定义:集合f[u,j]:所有从以u为根的子树中选,且总体积不超过j的选法 + * 属性:max最大价值 + * 集合划分:子树1,子树3,子树3 + * 划分依据:体积为0~m的子树,把每一棵子树看做一个物品做 + * 再根据体积划分子树:体积是0-m 有m+1总可能 + * 用一个数字表示一类方案 + * 把每一颗子树看做物品组,分组背包问题 + * 链式前向星建树 */ public class 有依赖的背包问题 { @@ -62,7 +63,7 @@ public class 有依赖的背包问题 { w[i] = sc.nextInt(); p = sc.nextInt(); if (p == -1) root = i; - else add(p, i); + else add(p, i);//p向i连一条边,父节点向子节点连边 } dfs(root); System.out.println(f[root][m]); @@ -74,7 +75,7 @@ public class 有依赖的背包问题 { dfs(e[i]); //以u为根的子树,每一棵子树都是一个分组背包问题 //抽象成2层 - for (int j = m - v[u]; j >= 0; j--) {//枚举体积 + for (int j = m - v[u]; j >= 0; j--) {//枚举体积,因为根节点必须要选,预留m-v[u for (int k = 0; k <= j; k++) {//枚举决策,分为以0~m的一些决策 f[u][j] = Math.max(f[u][j], f[u][j - k] + f[son][k]); //以u为根节点,在剩余体积为0~m-v[u]的情况下,选子树 @@ -95,11 +96,11 @@ public class 有依赖的背包问题 { static int N = 110; static int[] head = new int[N], e = new int[N], ne = new int[N]; - static int n, m, cnt = 1; + static int n, m, idx = 1; static void add(int a, int b) { - e[cnt] = b; - ne[cnt] = head[a]; - head[a] = cnt++; + e[idx] = b; + ne[idx] = head[a]; + head[a] = idx++; } } diff --git "a/ACWing/src/dp/\347\212\266\346\200\201\345\216\213\347\274\251dp/\345\223\210\345\257\206\345\260\224\351\241\277\345\233\236\350\267\257.java" "b/ACWing/src/dp/\347\212\266\346\200\201\345\216\213\347\274\251dp/\345\223\210\345\257\206\345\260\224\351\241\277\345\233\236\350\267\257.java" index ff6b2ff0fb8078e91cfc1d6eb63221e375779b61..0585f119525e3aad92e00993b9d67e7540721bb1 100644 --- "a/ACWing/src/dp/\347\212\266\346\200\201\345\216\213\347\274\251dp/\345\223\210\345\257\206\345\260\224\351\241\277\345\233\236\350\267\257.java" +++ "b/ACWing/src/dp/\347\212\266\346\200\201\345\216\213\347\274\251dp/\345\223\210\345\257\206\345\260\224\351\241\277\345\233\236\350\267\257.java" @@ -29,7 +29,7 @@ import static java.lang.Math.min; * 18 * 状压dp * 该图是完全图 - * 2的整数次幂-1的二进制位全是1111111 + * 2的整数次幂-1的二进制位全是1 * f[i,j]状态表示为从0走到顶点j状态为i的所有走法 */ public class 哈密尔顿回路 { diff --git "a/ACWing/src/dp/\347\212\266\346\200\201\345\216\213\347\274\251dp/\351\252\221\345\243\253.java" "b/ACWing/src/dp/\347\212\266\346\200\201\345\216\213\347\274\251dp/\351\252\221\345\243\253.java" index ce5e2678234a6deec8d67a439123da432b9381fe..0287d4caab0a500eae8ff150290d83be0545ea8c 100644 --- "a/ACWing/src/dp/\347\212\266\346\200\201\345\216\213\347\274\251dp/\351\252\221\345\243\253.java" +++ "b/ACWing/src/dp/\347\212\266\346\200\201\345\216\213\347\274\251dp/\351\252\221\345\243\253.java" @@ -39,10 +39,9 @@ import java.util.Scanner; * 另外,a中的合法状态可以转移到哪些合法的状态,也可以预处理出来存进向量b中。 * 本题方案数可能很大,需要用long long存储。 *
- * f[i,j,k] + * f[i,j,k] k为二进制数,表示在哪里放了国王 * 状态定义:所有只从前i行摆放,已经摆了j个国王,并且第i行的摆放状态是k的所有方案的集合 * 属性count - * */ public class 骑士 { public static void main(String[] args) { @@ -52,7 +51,7 @@ public class 骑士 { for (int i = 0; i < 1 << n; i++) { if (check(i)) { a.add(i);//去除相邻的放置方法 - cnt.add(count(i)); + cnt.add(count(i));//预处理i作为 } } int s = 0, t = 0, u = 0; diff --git "a/ACWing/src/dp/\347\212\266\346\200\201\346\234\272\346\250\241\345\236\213/\345\244\247\347\233\227\351\230\277\347\246\217.java" "b/ACWing/src/dp/\347\212\266\346\200\201\346\234\272\346\250\241\345\236\213/\345\244\247\347\233\227\351\230\277\347\246\217.java" index 195c25abf9cf095c9e29c179fe57c1a8e22beda3..51f62724532bbecfdb1f6ff15b07e58a66722c44 100644 --- "a/ACWing/src/dp/\347\212\266\346\200\201\346\234\272\346\250\241\345\236\213/\345\244\247\347\233\227\351\230\277\347\246\217.java" +++ "b/ACWing/src/dp/\347\212\266\346\200\201\346\234\272\346\250\241\345\236\213/\345\244\247\347\233\227\351\230\277\347\246\217.java" @@ -88,7 +88,12 @@ public class 大盗阿福 { * 状态转移,看成图论问题 * f[i,0] f[i,1] 表示:所有走了i步,且当前位于状态j的所有走法 * 属性:max - * 状态计算:f[i,0] 0->0 上一个不偷,这个一个也不偷, f[i-1,0] + * 状态0代表没偷,状态1代表偷了 + * 0->0 + * 0->1 + * 1->0 + * 只有这三种转移方式 + * 状态计算:f[i,0] 0->0 上一个不偷,这个一个也不偷, 对应就是f[i-1,0] * 1->0 上一个偷了,这个不偷 f[i-1,1] * f[i,1] 状态计算,只能0->1 上个不偷这个偷,f[i-1,0]+w[i] */ diff --git "a/ACWing/src/dp/\347\212\266\346\200\201\346\234\272\346\250\241\345\236\213/\350\202\241\347\245\250\344\271\260\345\215\2264.java" "b/ACWing/src/dp/\347\212\266\346\200\201\346\234\272\346\250\241\345\236\213/\350\202\241\347\245\250\344\271\260\345\215\2264.java" index 485f2aec203da81634e783736a0700abdaef3c91..d4a89311d5d35b2a5c12eec439f5ff9998a06b22 100644 --- "a/ACWing/src/dp/\347\212\266\346\200\201\346\234\272\346\250\241\345\236\213/\350\202\241\347\245\250\344\271\260\345\215\2264.java" +++ "b/ACWing/src/dp/\347\212\266\346\200\201\346\234\272\346\250\241\345\236\213/\350\202\241\347\245\250\344\271\260\345\215\2264.java" @@ -47,6 +47,8 @@ import java.util.Scanner; * f[i][j][1] = f[i-1][j][1],故f[i][j][1] = max(f[i-1][j][1],f[i-1][j-1][0]-w[i])。 * 从而状态转移方程就求出来了,下面考虑边界状态,f[i][0][0]表示第i天都未进行交易, * 收益是0,除此之外,f[i][[j][0]与f[i][0][1]的初始状态都应该是不合法的,设置为-INF。 + *
+ * 引入一层状态用来存交易次数
*/
public class 股票买卖4 {
public static void main(String[] args) {
@@ -68,7 +70,7 @@ public class 股票买卖4 {
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= k; j++) {
for (int l = 0; l < 2; l++) {
- f[i][j][l] = Integer.MIN_VALUE / 2;
+ f[i][j][l] = -0x3f3f3f3f;
}
}
}//初始化负无穷
@@ -79,10 +81,12 @@ public class 股票买卖4 {
f[i][j][0] = Math.max(f[i - 1][j][0], f[i - 1][j][1] + a[i]);
//卖出不消耗次数
f[i][j][1] = Math.max(f[i - 1][j][1], f[i - 1][j - 1][0] - a[i]);
- //昨天买的,今天不卖, 昨天交易次数为j-1没买,今天买上
+ //昨天买的,今天不动, 昨天交易次数为j-1没买,今天买上
//买入消耗次数
}
}
+
+ //查看进行i次交易能得到利润最大值
int res = 0;
for (int i = 0; i <= k; i++) {
res = Math.max(res, f[n][i][0]);
diff --git "a/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\344\271\260\344\271\246.java" "b/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\344\271\260\344\271\246.java"
index 2573cb9dd227f2e2957aa14421cd188162788c2a..008cbba56515724ec9529a084f3cd450521ea345 100644
--- "a/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\344\271\260\344\271\246.java"
+++ "b/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\344\271\260\344\271\246.java"
@@ -46,7 +46,7 @@ public class 买书 {
}
static int n = 400;
- static int v[] = {0, 10, 20, 50, 100};
+ static int[] v = {0, 10, 20, 50, 100};
static int[] dp = new int[1010];
static int[][] f = new int[5][1010];
}
diff --git "a/ACWing/src/dp/\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/dp/\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 58078b6e58646c1b0cced085807a0d2d8d844d86..65a3f3d13439f0410e93382ead591b1fb9a93306 100644
--- "a/ACWing/src/dp/\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/dp/\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"
@@ -5,8 +5,9 @@ import java.util.Scanner;
/**
* 有N组物品,每个组只能选1个,
* 求最大价值
- * 转换成01背包问题,
+ * 类似01背包问题,
* 状态定义为f[i,j]:前i组物品可选,体积不超过j的所有选法最大值
+ * 属性max
* 划分依据,选第i组物品的第几个,还是不选第i组物品
* 状态划分:选第i组物品的第1个,选第i组物品的第2个,选第i组物品的第s[i]个,不选第i组物品
* 状态计算:显然不选第i组物品就是f[i-1,j]
diff --git "a/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\244\232\351\207\215\350\203\214\345\214\2051.java" "b/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\244\232\351\207\215\350\203\214\345\214\2051.java"
index f81246e43829932b8b4f225ce272e686981aca8d..a0e12e83995303757227353c38f318940b517094 100644
--- "a/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\244\232\351\207\215\350\203\214\345\214\2051.java"
+++ "b/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\244\232\351\207\215\350\203\214\345\214\2051.java"
@@ -5,8 +5,10 @@ import java.util.Scanner;
/**
* 完全背包变形多重背包:每样物品最多选s[i]个
* 同理状态定义:f[i,j]代表体积为j前i个物品可选的最大价值
+ * 划分依据:选第i个物品多少个
* 状态划分:选0个第i个物品,选1个第i个物品,选2个第i个物品,选3个第i个物品....选s[i]个第i个物品
* 状态计算,不失一般性,选k个:f[i-1,j-k*v[i]]+w[i] 只有在j>=k*v[i]并且k<=s[i]的时候才合法
+ * O(n^3)
*/
public class 多重背包1 {
public static void main(String[] args) {
diff --git "a/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\244\232\351\207\215\350\203\214\345\214\205\344\272\214\350\277\233\345\210\266\344\274\230\345\214\226.java" "b/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\244\232\351\207\215\350\203\214\345\214\205\344\272\214\350\277\233\345\210\266\344\274\230\345\214\226.java"
index b11d43aa340049d6607da72d0471342060635a72..73716c72a144d7b8dfe7623e441d99e1e1de2161 100644
--- "a/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\244\232\351\207\215\350\203\214\345\214\205\344\272\214\350\277\233\345\210\266\344\274\230\345\214\226.java"
+++ "b/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\345\244\232\351\207\215\350\203\214\345\214\205\344\272\214\350\277\233\345\210\266\344\274\230\345\214\226.java"
@@ -17,6 +17,32 @@ import java.util.Scanner;
*/
public class 多重背包二进制优化 {
public static void main(String[] args) {
+ Scanner sc = new Scanner(System.in);
+ N = sc.nextInt();
+ V = sc.nextInt();
+ int a, b, c;
+ for (int i = 1; i <= N; i++) {
+ v[i] = sc.nextInt();
+ w[i] = sc.nextInt();
+ s[i] = sc.nextInt();
+ }
+ for (int i = 1; i <= N; i++) {
+ for (int k = 1; k <= s[i]; k *= 2) {//直接变成01背包
+ for (int j = V; j >= v[i]; j--) {
+ dp[j] = Math.max(dp[j - v[i]] + w[i], dp[j]);
+ }
+ s[i] -= k;
+ }
+ if (s[i] > 0) {
+ for (int j = V; j >= v[i]; j--) {
+ dp[j] = Math.max(dp[j - v[i]] + w[i], dp[j]);
+ }
+ }
+ }
+ System.out.println(dp[V]);
+ }
+
+ static void yuchuli() {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
V = sc.nextInt();
@@ -38,7 +64,7 @@ public class 多重背包二进制优化 {
v[cnt] = a * c;
w[cnt] = b * c;
}
- }
+ }//二进制预处理
N = cnt;//二进制优化后,一共有n个物品,01背包
for (int i = 1; i <= N; i++) {
for (int j = V; j >= v[i]; j--) {
@@ -48,8 +74,9 @@ public class 多重背包二进制优化 {
System.out.println(dp[V]);
}
- static int cnt=0;
- static int dp[] = new int[2010];
+ static int cnt = 0;
+ static int[] dp = new int[2010];
static int[] v = new int[1000 * 13], w = new int[1000 * 13];
+ static int[] s = new int[13000];
static int N, V;
}
diff --git "a/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\225\260\345\255\227\347\273\204\345\220\210.java" "b/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\225\260\345\255\227\347\273\204\345\220\210.java"
index 5c8ab47747cf999e2a8f959a8c895a1a141f532a..a567d4514bd53dcfaf907394d73194324b917f1d 100644
--- "a/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\225\260\345\255\227\347\273\204\345\220\210.java"
+++ "b/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\225\260\345\255\227\347\273\204\345\220\210.java"
@@ -23,11 +23,15 @@ import java.util.Scanner;
* M看做背包容量,每一个数看作物品,把Ai看做体积
* 求出总体积为M的所有方案数量
* 状态定义:f[i,j],集合:所有只从前i个物品选,且恰好总体积是j的方案总和
- * 属性:count
+ * 属性:count,方案数
* 状态划分:包含第i个,不包含第i个
+ * 划分依据:包不包含当前物品i
* 状态计算:不包含第i个->f[i-1,j]
* 包含第i个->f[i-1,j-v[i]]
* 状态合并:
+ * 显然:从前i个物品选且总体积恰好为j方案应当等于如下
+ * 前i-1种物品且总体积为j的方案加上前i-1种物品可选总体积恰好为j-v[i]
+ * 因为前i-1种物品可选总体积恰好为j-v[i]再加上第重量为v[i]的第i种物品恰好是一种合法方案
* 所以f[i,j]=f[i-1,j]+f[i-1,j-v[i]]
*/
public class 数字组合 {
@@ -36,15 +40,15 @@ public class 数字组合 {
n = sc.nextInt();
m = sc.nextInt();
for (int i = 1; i <= n; i++) {
- A[i] = sc.nextInt();
+ v[i] = sc.nextInt();
}
// one();
f[0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= m; j++) {
f[i][j] = f[i - 1][j];
- if (j >= A[i])
- f[i][j] += f[i - 1][j - A[i]];
+ if (j >= v[i])
+ f[i][j] += f[i - 1][j - v[i]];
}
}
System.out.println(f[n][m]);
@@ -54,14 +58,14 @@ public class 数字组合 {
static void one() {
dp[0] = 1;
for (int i = 1; i <= n; i++) {
- for (int j = m; j >= A[i]; j--) {
- dp[j] += dp[j - A[i]];
+ for (int j = m; j >= v[i]; j--) {
+ dp[j] += dp[j - v[i]];
}
}
System.out.println(dp[m]);
}
- static int[] A = new int[110];
+ static int[] v = new int[110];
static int[][] f = new int[110][10010];
static int[] dp = new int[10010];
static int n, m;
diff --git "a/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\231\256\351\200\232\344\272\214\347\273\264\350\264\271\347\224\250\350\203\214\345\214\205.java" "b/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\231\256\351\200\232\344\272\214\347\273\264\350\264\271\347\224\250\350\203\214\345\214\205.java"
index edbf04849e1900f777d5bd0ce7c1685abeaa4c7f..64ee398673f7a057d6f5bf22e7175caa3bca6888 100644
--- "a/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\231\256\351\200\232\344\272\214\347\273\264\350\264\271\347\224\250\350\203\214\345\214\205.java"
+++ "b/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\231\256\351\200\232\344\272\214\347\273\264\350\264\271\347\224\250\350\203\214\345\214\205.java"
@@ -30,7 +30,7 @@ import java.util.Scanner;
* 输出样例:
* 8
* 分析:背包有重量和体积限制,每个物品可选可不选,求最大价值
- * 状态表示:f[i,j,k] 所有只从前i种物品选,总体积超过j,总重量不超过k的选法
+ * 状态表示:f[i,j,k] 所有只从前i种物品选,总体积不超过j,总重量不超过k的选法
* 属性: max 最大价值
* 状态划分:所有包含第i个物品的选法,所有不包含物品i的选法
* 不选第i个物品:f[i-1,j,k]
diff --git "a/ACWing/src/dp/\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/dp/\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"
index f49803c00f06473f9db53a25cbcaef0446d9a965..b62357988e7faca3897eacf07ab95f518972d3e3 100644
--- "a/ACWing/src/dp/\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/dp/\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"
@@ -29,12 +29,14 @@ import java.util.Scanner;
* 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个是合法的方案。
+ * 如果选,选几个,只需要找出其中的一个k,
+ * 使得f[i][j] == f[i-1][j-k]+w[i][k]即可使得第i个物品选k个是合法的方案。
*/
public class 机器分配 {
public static void main(String[] args) {
@@ -59,8 +61,9 @@ public class 机器分配 {
int j = m;
for (int i = n; i != 0; i--) {//倒序往前找决策
for (int k = 0; k <= j; k++) {
+ //k从0开始使得存在不选第i组物品的方案
if (f[i][j] == f[i - 1][j - k] + w[i][k]) {
- way[i] = k;
+ way[i] = k;//这个是倒序存的,所以最终可以正序输出
j -= k;
break;
}
diff --git "a/ACWing/src/dp/\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/dp/\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 c75edbd681ba5b26217159a52bbed5f16f3b2620..6ddc404baeb2627167de11ed90d45568b81b63ee 100644
--- "a/ACWing/src/dp/\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/dp/\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"
@@ -33,12 +33,13 @@ public class 混合背包 {
t[i] = sc.nextInt();
}
for (int i = 1; i <= N; i++) {
- if (t[i] == 0) {
+ 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;
+ if (t[i] == -1) t[i] = 1;//01背包
+ //多重背包转01背包
for (int k = 1; k <= t[i]; k *= 2) {
for (int j = V; j >= k * v[i]; j--) {//把k个物品看成可选可不选的一个物品,01背包
f[j] = Math.max(f[j], f[j - k * v[i]] + w[i] * k);
diff --git "a/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\275\234\346\260\264\345\221\230\344\272\214\347\273\264\350\264\271\347\224\250\350\203\214\345\214\205.java" "b/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\275\234\346\260\264\345\221\230\344\272\214\347\273\264\350\264\271\347\224\250\350\203\214\345\214\205.java"
index ab36ef62bf796fcc20cdeb417d8687e7c4062b0c..477c9f05914d87c302b01b1dd6e9a5f6578be52d 100644
--- "a/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\275\234\346\260\264\345\221\230\344\272\214\347\273\264\350\264\271\347\224\250\350\203\214\345\214\205.java"
+++ "b/ACWing/src/dp/\350\203\214\345\214\205\346\250\241\345\236\213/\346\275\234\346\260\264\345\221\230\344\272\214\347\273\264\350\264\271\347\224\250\350\203\214\345\214\205.java"
@@ -35,6 +35,7 @@ import java.util.Scanner;
* 4 20 119
* 【输出样例】
* 249
+ * 最低状态定义稍有区别,状态定义恰好和至少的区别做法就不一样
* 显然三个东西,看如何划分:
* 物品: 氧气 氮气 重量
* a b c
@@ -51,6 +52,7 @@ import java.util.Scanner;
* 在状态定义恰好是j,恰好是k的时候
* f[0,0,0]=0 是合法的
* f[0,j,k]=是非法的,因为只选0个不可能达到恰好是j,或者k
+ * 应该f[0,j,k]=正无穷
*/
public class 潜水员二维费用背包 {
public static void main(String[] args) {
@@ -59,27 +61,27 @@ public class 潜水员二维费用背包 {
m = sc.nextInt();//需要的氮气
shu = sc.nextInt();//有多少个气缸
for (int i = 1; i <= shu; i++) {
- o[i] = sc.nextInt();
- d[i] = sc.nextInt();
+ v1[i] = sc.nextInt();
+ v2[i] = sc.nextInt();
w[i] = sc.nextInt();
}
two();
}
static int n, m, shu;
- static int[] o = new int[1010], d = new int[1010], w = new int[1010];
+ static int[] v1 = new int[1010], v2 = new int[1010], w = new int[1010];
static int[][][] f = new int[23][88][1010];
static int[][] dp = new int[5000][1600];
static void two() {
- for (int i = 0; i < dp.length; i++) {
- Arrays.fill(dp[i], Integer.MAX_VALUE - 10000);
+ for (int[] ints : dp) {
+ Arrays.fill(ints, 0x3f3f3f3f);
}
dp[0][0] = 0;
for (int i = 1; i <= shu; i++) {
for (int j = n; j >= 0; j--) {
for (int k = m; k >= 0; k--) {
- dp[j][k] = Math.min(dp[j][k], dp[Math.max(j - o[i], 0)][Math.max(k - d[i], 0)] + w[i]);
+ dp[j][k] = Math.min(dp[j][k], dp[Math.max(j - v1[i], 0)][Math.max(k - v2[i], 0)] + w[i]);
}
}
}
diff --git "a/ACWing/src/dp/\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/dp/\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 7f24610ae0e6e4cd7bfec1bd99609f1bd6d4cbce..567a318a18ef1047d55c2e97e679d0a76894e943 100644
--- "a/ACWing/src/dp/\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/dp/\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"
@@ -28,9 +28,15 @@ import java.util.Scanner;
* 4 6
* 输出样例:
* 1 4
+ * f[i,j]=max(f[i-1,j],f[i-1,j-v[i]]+w[i])
+ * 其实判断出决策的是哪一项
* 对应图论最短路问题
* f[n-1,m]->f[n,m]边权重为0
* f[n-1,m-v[i]]+w[i]->f[n,m] 边权重为w[i]
+ * 也就是倒着求,f[n,m]是从哪一条边转移过来的
+ * 直接判断是f[n-1,m]==f[n,m]还是f[n-1,m-v[i]]+w[i]==f[n,m]
+ * 如果都相等,说明可选第i号物品,如果只有右边相等说明必选,如果只有左边相等说明不能选
+ * 就能判断决策
* 要求字典序最小:
* 可能最大价值有多种方案
* 对于一个物品:有三种情况,必选,可选,不能选
@@ -47,14 +53,14 @@ public class 背包问题求具体方案 {
v[i] = sc.nextInt();
w[i] = sc.nextInt();
}
- for (int i = n; i >= 1; i--) {
+ for (int i = n; i >= 1; i--) {//倒序枚举每个物品,方便倒推方案
for (int j = 0; j <= m; j++) {
f[i][j] = f[i + 1][j];
if (j >= v[i])
f[i][j] = Math.max(f[i][j], f[i + 1][j - v[i]] + w[i]);
}
}
- //f[1][m]是最大值
+ //f[1][m]是最大值,是结果
int j = m;
for (int i = 1; i <= n; i++) {//1~n个物品可选
if (j >= v[i] && f[i][j] == f[i + 1][j - v[i]] + w[i]) {
diff --git "a/ACWing/src/dp/\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\346\226\271\346\241\210\346\225\260\351\207\217.java" "b/ACWing/src/dp/\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\346\226\271\346\241\210\346\225\260\351\207\217.java"
new file mode 100644
index 0000000000000000000000000000000000000000..425f9301ee71756d1c625a627f096278ec75099f
--- /dev/null
+++ "b/ACWing/src/dp/\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\346\226\271\346\241\210\346\225\260\351\207\217.java"
@@ -0,0 +1,79 @@
+package dp.背包模型;
+
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
+ * 第 i 件物品的体积是 vi,价值是 wi。
+ * 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
+ * 输出 最优选法的方案数。注意答案可能很大,请输出答案模 10^9+7 的结果。
+ * 输入格式
+ * 第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
+ * 接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。
+ * 输出格式
+ * 输出一个整数,表示 方案数 模 109+7 的结果。
+ * 数据范围
+ * 0