算法分析
-
1、由于题目要求求字典序最小的方案,因此从
1
到n
中,每个物品有3
种情况-
(1)只能选,则必须选
-
(2)不能选,则必不选
-
(3)可选可不选,则必须选
在前面物品能选的情况下优先选择前面的物品
-
-
2、为了满足上述条件,因此需要从第
n
个物品遍历到第1
个物品,求出当前背包的最大总价值f[1][m]
-
3、再从第
1
个物品遍历到第n
个物品,其中f[i][j]
为当前最优情况,若满足-
(1)
f[i][j] == f[i + 1][j]
,则表示f[i][j]
是从f[i + 1][j]
状态转移过来的 -
(2)
f[i][j] == f[i + 1][j - v[i]] + w[i]
,则表示f[i][j]
是从f[i + 1][j - v[i]]
状态转移过来的
从而找出字典序最小的路径方案
-
完全背包求具体方案 LeetCode 1449. 数位成本和为目标值的最大数字
时间复杂度 $O(n^2)$
参考文献
算法提高课
Java 代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
static int N = 1010;
static int[] v = new int[N];
static int[] w = new int[N];
static int[][] f = new int[N][N];
static int n;
static int m;
public static void main(String[] args) throws IOException{
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String[] s1 = reader.readLine().split(" ");
n = Integer.parseInt(s1[0]);
m = Integer.parseInt(s1[1]);
for(int i = 1;i <= n;i++)
{
String[] s2 = reader.readLine().split(" ");
v[i] = Integer.parseInt(s2[0]);
w[i] = Integer.parseInt(s2[1]);
}
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] 是最大值
int j = m;
for(int i = 1;i <= n;i ++)
{
//若当前有选该值则记录
if(j >= v[i] && f[i][j] == f[i + 1][j - v[i]] + w[i])
{
System.out.print(i + " ");
j -= v[i];
}
}
}
}
喵喵
为什么压缩成一维答案不对呢
一维会丢失状态,无法还原。只能是二维做此题。
可不可以正向算最大价值 逆向推方案呢
那就记呗,第一次获取到最大值时,用vector或者静态数组记录下当前的最小序号。
正向算最大值, 逆向推方案的话, 较小的字典序方案就会被后来的较大字典序方案给覆盖掉, 导致最后输出的是较大字典序
优秀。点赞~~~
请问如果 在可选可不选的时候,必选。
若最终答案是 $1\;2$ ,$3$ 可选可不选,按照上述思路,求得最终答案为 $1\;2\;3$ 。
但这样不就不满足字典序最小了吗?
大哥问一下为什么满足做个条件就需要从N~1枚举啊,这里没想明白
(1)只能选,则必须选
(2)不能选,则必不选
(3)可选可不选,则必须选
在前面物品能选的情况下优先选择前面的物品
1、如果要求具体方案的问题,就必须通过状态的状态转移等式去找路径,这里要找的是字典序最小,即如果存在靠前的物品可以选,那我们就尽可能的选靠前的物品
2、从
1
枚举到N
,和从N
枚举到1
,计算背包能装的总价值最大,其实求出来的结果是一样的,只是选的顺序不一样,可是题目要求是字典序最小,因此从N
枚举到1
可以计算出f[1][m]
是背包的最大价值,由于该状态是由第二个物品选和不选两个状态转移过来的,即考虑f[i][j]
是怎么来的,是由上一个物品选或者不选来的,即从f[i + 1][j]
或者f[i + 1][j - v[i]] + w[i]
转移过来的,因此就可以通过当前的最优值,找到上一个的最优值,就可以知道上一个最优值对应的物品到底有选还是没选3、由于要求字典序最小,因此需要从第一个物品的最优状态值开始往第二,第三个物品…的最优状态值找
懂了大哥,从后往前找才能f[i][j]是咋来的,感谢
没错没错哈哈哈
说的太好了
牛比
大神大神带我飞