首页 > 其他分享 >[杂记] 01背包记录路径

[杂记] 01背包记录路径

时间:2022-12-06 14:46:17浏览次数:34  
标签:pre 01 int 复杂度 背包 杂记 物品 dp

[杂记] 01背包记录路径

众所周知,01背包的时间复杂度是\(O(nm)\)(n为物品数量,m为背包容量),空间复杂度是\(O(m)\)。如果还需要输出最优解中的所有物品的话,时间复杂度不变,空间复杂度呢?

你的第一反应可能是:我很快就可以给出一个空间复杂度也是\(O(m)\)的算法啊?

但实际上这个算法是有问题的:

int n;		// 物品数量
int m;		// 背包容量
int w[N];	// 物品重量
int v[N];	// 物品价值
int dp[M];	// dp数组
int pre[M];	// 路径

void package01() {
    for (int i = 1; i <= n; i ++) {
        for (int j = m; j >= w[i]; j --) {
            if (dp[j] < dp[j-w[i]] + v[i]) {
                dp[j] = dp[j-w[i]] + v[i];
                pre[j] = i;
            }
        }
    }

    int j = m;
    while (pre[j] != 0) {
        int last = pre[j];
        printf("%d, ", last);
        j -= w[last];
    }
}

这样写有什么问题呢?

当然有!

比如对于下面的样例:

n = 3;
m = 4;
w[] = {1, 1, 2};
v[] = {1, 1, 4};

输出结果就是

3, 3,

第三个物品被用了两次。

这时你可能恍然大悟,因为在第三个物品加入后,pre[2]被更新为了3,所以就丢失了前两个物品的路径。

本质原因在于,一开始的01背包本来就是二维数组\(dp[i][j]\),表示“只使用前i个物品,背包容量为j时的最大价值”,这时\(pre[i][j]\)的意义就是“只使用前i个物品,背包容量为j,达到最大价值时最后一个购买的物品”。转移是:

if (dp[i-1][j] > dp[i-1][j-w[i]] + v[i]) {
	dp[i][j] = dp[i-1][j-w[i]] + v[i];
	pre[i][j] = i;
}
else {
	dp[i][j] = dp[i-1][j];
	pre[i][j] = pre[i-1][j];
}

路径是:

int i = n, j = m;
while (pre[i][j] != 0) {
    int last = pre[i][j];
    printf("%d, ", last);
    i = last - 1; 
    j -= w[last];
}

如果把pre压缩为1维,相当于最后只剩下\(pre[n][.]\),前面\(pre[<n][.]\)的路径信息就丢失了,这样就没法输出完整路径了。

那有没有时间复杂度还是\(O(nm)\),空间复杂度低于\(O(nm)\)的做法呢?

好吧我是没想出来。

不过倒是有一种能让空间降低32倍的做法:将pre变成一个01数组,\(pre[i][j]=1\)表示“只使用前i个物品,背包容量为j,达到最大价值时最后一个购买的物品就是i”。这样也能输出完整的路径。

int i = n, j = m;
while (i != 0) {
    while (!pre[i][j])
        i --;
    printf("%d, ", i);
    j -= w[i];
    i --;
}

如果有高人能给出空间复杂度低于\(O(nm)\)的做法,欢迎交流。

标签:pre,01,int,复杂度,背包,杂记,物品,dp
From: https://www.cnblogs.com/CQzhangyu/p/16955152.html

相关文章

  • 2019.10.26日学习总结
     今天纪老师带着我们探讨了,更新软件的意义、薪资对我们而言究竟意味着什么、为什么要树立终身学习的想法。1:首先说一下,更新软件的意义,为什么要更新软件,这件事情对于我们而......
  • 2019.10.27二进制学习总结
    今天上午大家讨论学习了二进制。我总结了二进制的以下几个规律。1:十进制中2的次方数每增加1它相对应的二进制的数位次就增加1位。2:二进制的每一位数都是都是有循环变化的。3......
  • MyBatis ORA-01465: 无效的十六进制数字
    MyBatis在插入Oralce时报:ORA-01465:无效的十六进制数字解决方法:#插入或更新时String->BLOB字段:RAWTOHEX(#{字段名})String->DATE:to_date(#{字段名},'yyyy-mm-......
  • 【杂记】04:FPGA
    【如何才算学会了FPGA?】https://www.bilibili.com/video/BV1KP411M7CU如何才算是学会了?独立、不参考书本代码的情况下,完成所有实例,才算是入门FPGA。学FPGA需要有电路基础,模......
  • 300010 原位标注和集中标注的区别
    <?phpheader('Content-Type:text/html;charset=utf-8');define('ROOT',$_SERVER['DOCUMENT_ROOT']);includeROOT.'/assets/php/head.php';$tit='原位标注和集中......
  • WALLYS/dr6018 vs dr6018s/ipq6018/ipq6010/ipq6000/SFP/ OpenWRT 2x2 2.4G&5G indust
    dr6018vsdr6018s/ipq6018/ipq6010/ipq6000/SFP/OpenWRT2x22.4G&5Gindustrialwifi6moudle NextwewillintroduceourDR6018andDR6018S.Thisboardissim......
  • Solon v1.11.3 发布,第101个发布版本喽
    一个更现代感的Java应用开发框架:更快、更小、更自由。没有Spring,没有Servlet,没有JavaEE;独立的轻量生态。主框架仅0.1MB。@ControllerpublicclassApp{publ......
  • 使用DevExpress WPF主题设计器轻松创建Office 2019绿色主题(一)
    DevExpressWPF拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpressWPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专......
  • C++入门(一)----Visual C++ 6.0和Visual Studio 2019 的安装与使用
    VisualC++6.0的安装与使用VisualStudio2019的安装与使用下载链接:​​​https://visualstudio.microsoft.com/zh-hans/free-developer-offers/​​​VisualStudio201......
  • 2018,React Native第三方组件库汇总
    2018,ReactNative第三方组件库汇总老实人工程师​关注他 10人赞同了该文章移动跨平台框架ReactNative经过4年的发展,其生态已经变得异常丰富,在......