软了个考——背包就六个格子,还不就是看局势出装备

2024-05-05 18:08

本文主要是介绍软了个考——背包就六个格子,还不就是看局势出装备,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

    上次一不小心装了个大的,放出豪言要讲动态规划,结果在组内讲的时候还讲错了,幸好凭借多年演技,沉着冷静,胆大心细,走位逼真,操作细腻,瞬间爆炸,完成反杀。。。额,后边这个没有。终于是没丢人丢到5楼去。

    好了,既然是说背包问题,那就先把问题复制过来。

    问题描述:

    挖掘机技术究竟哪家强?

    额。。。不对,是这个。。。

    给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为Weight。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?

    这里有一个前提,物品能不能拆,能拆是一种解法,不能拆又是另一种解法。先说说不能拆的情况。

    在不能拆的情况下,各个物品只有两种状态,放or不放,所以这种不能拆的背包又叫做0-1背包问题,放用1表示,不放用0表示。

    你想,或者不想它,它就在那里,不言不语。

    你放,或者不放它,解就在那里,是零是一。

    你拆,或者不拆它,说不定在哪里,看性价比。

    来我包里,或者,快到我碗里~~~

    好了,开始解我们的问题。

    第一种解法看看我们的通用解题法——回溯法。因为本身回溯法的思想是,先试试,不行再回来,这样我们就可以解决大部分的问题了。那么就背包问题来看,回溯法就是,第一次放进去k个物品,得出一个包内的价值,此时背包剩下的重量,不能再放物品了,然后取出一个,换别的第一次没放进去的物品,看一下能不能得出比第一次的价值大的解来,如果不能,就在取出一个来,然后就这样下去。

    比如我们第一次放入了123,这三个物品,那么第一次应该拿出3来,然后考虑,456。。。这些放进去能不能有更多的价值。再考虑2拿出来,3456。。。会不会有更多的价值,也就是说,我们取出哪个物品,我们就只考虑背包没有那个物品的解。

    这里有一个问题,回溯法求解之前要先按照性价比排序,这里如果不是米老师讲的话我还真没看出来。

    所以我们看一些回溯法资料的时候,都是用二叉树的深度优先搜索来表示整个过程的,这个咱们那本书上有,愿意看的看看,相信看了我说的这个过程之后应该就能看懂那个树了。

    接下来就是大伙表示很看不懂的代码了。

    回溯法中背包问题的代码有两部分,求出解的过程,和计算背包物品价值上界。

public class Pack{int[] v;        //物品价值数组int[] w;        //物品重量数组/// <summary>/// 根据贪心法,计算背包价值上界/// </summary>/// <param name="v">当前背包价值</param>/// <param name="w">当前背包重量</param>/// <param name="k">已经放进去的物品数</param>/// <param name="Weight">背包总重量</param>/// <returns>价值上界</returns>public double Bound(int cv, int cw, int k, int Weight){int b = cv;          //价值上界       int c = cw;          //保存当前背包剩余容量//背包放入物品后,剩余的容量,和剩余容量能获得的最大价值for (int i = 0; i < k + 1; i++){c = c + w[i];       //已经放入的物品重量if (c < Weight)     //若未超过背包总重量b = b + v[i];   //已经放入的物品价值else                //超过总重量{return (b + (1 - (c - Weight) / w[i] * v[i]));//加上最后一点容量,能放入部分下一个物品的价值}}return b;           //返回价值上界}/// <summary>/// 整个二叉树的回溯过程/// </summary>/// <param name="Weight">背包总重量</param>/// <param name="n">物品个数</param>/// <param name="w">物品重量数组</param>/// <param name="v">物品价值数组</param>/// <param name="MaxW">获得最大价值时的重量</param>/// <param name="MaxV">获得的最大价值</param>/// <param name="X">最优解</param>/// <returns>返回X</returns>public int[] BKNAP1(int Weight, int n, int[] w, int[] v, int MaxW, int MaxV, int[] X){int cw = 0;         //当前背包重量,current weightint cp = 0;         //当前背包价值, current priceint k = 1;            //数组下标,从1开始int[] Y;            //解数组,物品k放入背包,则Y[k]=1MaxV = -1;          //最大价值,这里等于几都行,只是一个初始值while (true){//如果物品能放入背包while (k < n + 1 && cw + w[k] < Weight + 1){cw = cw + w[k]; //当前重量加上放入物品重量cp = cp + v[k]; //当前价值加上放入物品价值Y[k] = 1;       //表示物品k放入背包k = k + 1;      //下一个物品}if (k > n)          //若所有物品都能放入{MaxV = cp;      //当前价值=最大价值MaxW = cw;      //当前重量等于最大重量k = n;          //k等于物品数X = Y;          //最优解为Y}else{Y[k] = 0;       //若不是所有的都能放入,从不能放入之后开始每个都为0}//如果价值上界都小于当前最大价值while (Bound(cp, cw, k, Weight) < MaxV + 1){//找到无法放入的第K个物品while (k != 0 && Y[k] != 1){k = k - 1;      //往前找}if (k == 0)         //如果找到最后一个,说明一个物没放{return Y;}Y[k] = 0;           //将当前物品取出cw = cw - w[k];cp = cp - v[k];}k = k + 1;              //判断下一个物品return X;}}}

    伪代码实在是打着麻烦,翻一个熟悉的。书上的代码和我的有点点不一样,一句一句的写注释也是挺难的,在听了米老师的课之后才算是把价值上界想通了。我就不再讲了,最后可能有一点错误,万一我理解错了希望有人指出来。

    回溯可能看起来比较抽象,贪心应该就简单多了,就是突出一个硬塞,那个性价比高塞哪个。

    贪心的物品有时候是可以拆的,可以拆的时候就要考虑拆哪个更值钱,所以一切的关键还是在算前排序上。

/// <summary>/// 贪心算法/// </summary>/// <param name="v">物品价值数组</param>/// <param name="w">物品重量数组</param>/// <param name="weight">背包总重量</param>/// <param name="x">解</param>/// <param name="n">物品数</param>public int[] Greedy(int[] v, int[] w, int weight, int[] x, int n){//初始化解数组for (int i = 0; i < n; i++){x[i] = 0;}int c = weight;         //剩余重量//向背包添加物品for (int i = 1; i < n + 1; i++){//能放就放if (w[i] <= c){x[i] = 1;       //表示放入c = c - w[i];   //剩余容量减当前物品容量}//如果放不进去了if (i <= n && w[i]>c){x[i] = c / w[i];//按照剩余容量与物品重量的比例放入c = 0;          //放入之后背包容量为0}}return x;		    //返回解}

    看起来贪心法简单多了是不是?我这里改了一下书上的算法,书上是没有最后c=0这句话的,但是实际上应该是有的,不信自己写写看~

    最后一种是动态规划,虽然当初分配给我的就是这个,我看的也最多,但还是觉得动态规划是最难的,尤其涉及到老师说的那个最优子结构,我看的时候都没想过,只注意了子问题的重叠。

    动态规划的代码实际上就是米老师带着我们看的那个表的画表的过程,我当时实在是看不懂那个是什么玩意,就自己手动按照代码画了一个,米老师说的很对,动手画上几行就全懂了。而求解的过程是另一个过程,其实就是个简单的判断,下面看我接着翻译。

/// <summary>/// 动态规划法/// </summary>/// <param name="n">考虑前几个物品</param>/// <param name="Weight">背包容量</param>/// <returns>在j的重量下考虑前i个物品时的价值</returns>public int[,] DynamicProgramming(int n, int Weight){int[,] c;           //二维数组,存放在j的容量下考虑前i个物品时的价值//考虑0个物品时总价值全是0for (int k = 0; k < Weight + 1; k++){c[0, k] = 0;}//从前1个物品开始考虑for (int i = 1; i < n + 1; i++){c[i, 0] = 0;        //背包总重是0时,总价值全是0//从背包容量为1时开始考虑for (int j = 1; j < Weight + 1; j++){if (w[i] <= j)      //如果当前物品重量,小于背包容量,加入考虑范围{if (v[i] + c[i - 1, j - w[i]] >= c[i - 1, j])//如果当前物品价值,加上未放入该物品时的最大价值,大于等于不放入该物品的价值{c[i, j] = v[i] + c[i - 1, j - w[i]];//那么这个物品放入,当前总价值更新}else{   c[i, j] = c[i - 1, j];//否则不放入该物品,当前总价值不变}}else                //当前物品重量,超过背包容量,不放入考虑范围             {c[i, j] = c[i - 1, j];//当前总价值不变}}return c;}}/// <summary>/// 求解/// </summary>/// <param name="c">刚才求出的价值数组</param>/// <param name="j">考虑背包重量为j</param>/// <param name="n">物品总数</param>/// <returns>解</returns>public int[] OutPut(int[,] c, int j,int n){int[] x;        //解数组//从最后一个物品开始考虑,不考虑第一个物品for (int i = n; i > 1; i--){//如果考虑第i个物品的价值,等于第i-1个物品,那么表示这个物品没有放入if (c[i,j]==c[i-1,j]){x[i]=0;     //表示没放入}else{x[i] = 1;   //表示放入j=j-w[i];   //当前考虑的重量,减去物品i的重量}}//如果只考虑第一个物品时价值为0,那么表示第一个物品没放入if (c[1,j]==0){x[1] = 0;}else{x[1] = 1;}}

    至于米老师的那种动态规划法,我是没能力在这么短的时间之内把代码写出来,等到软考之后或许会仔细想想。

    好了,这次是把以前没写够的长度,一次都写得差不多了,以前确实觉得算法难,但是真的仔细看下去,动手写写那些过程,书上的例子都是很基础的,再次奉劝那些说这个难那个难的同学们,静下心来多看两眼吧。

以上


这篇关于软了个考——背包就六个格子,还不就是看局势出装备的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/962333

相关文章

秋招突击——6/22——复习{区间DP——加分二叉树,背包问题——买书}——新作{移除元素、实现strStr()}

文章目录 引言复习区间DP——加分二叉树个人实现 背包问题——买书个人实现参考实现 新作移除元素个人实现参考思路 找出字符串中第一个匹配项的下标个人实现参考实现 总结 引言 今天做了一个噩梦,然后流了一身汗,然后没起来,九点多才起床背书。十点钟才开始把昨天那道题题目过一遍,然后十一点才开始复习题目,为了不耽误下午的时间,所以这里的就单纯做已经做过的题目,主打一个有量,不在学

采药问题 01背包

Description:辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如何用动态规划解决0-1背包问题(C语言实现)

对于一组不同重量、不可分割的物品,我们需要选择一些装入背包,在满足背包最大重量限制前提下,背包中物品总重量的最大值是多少?假设此时是5个物品,2,2,4,6,3,然后背包最大承载两是9. 假如我们使用回溯算法解决该问题, 代码如下 int maxW = 0; //最大重量int n = 5; //物品数目int w = 9; // 背包最大重量int weight[] = {2,2,4,

从网易校招编程题谈起,轻松理解有趣的0-1背包问题

从网易的一道算法题开始 最近在准备春招实习,偶然做到网易的一道编程题,一方面找了很多博客看的云里雾里,这里特别写下解题的思路和逻辑,一方面加深印象,另一方面供需要的你学习参考。好了,话不多说,开始吧。本文提供思路,并给出Java代码实现例子,供大家参考。 先睹为快 来源:网易2017春招笔试真题编程题 时间限制:1秒 空间限制:32768K 一种双核CPU的两个核能够同时的处理任务,现在有

算法学习014 0-1背包问题 c++动态规划算法实现 中小学算法思维学习 信奥算法解析

目录 C++0-1背包 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、运行结果 五、考点分析 六、推荐资料 C++0-1背包 一、题目要求 1、编程实现 有 N 件物品和一个容量为 M的背包,每件物品有各自的价值且只能被选择一次,要求在有限的背包容量下,装入的物品总价值最大。 2、输入输出 输入描述:第一行输入两个整数,分别表示

实现编程理论的六个原则④对称性

是什么 对称性一般指事物中对某种变换保持不变的性质。以图形中的对称性来说,“轴对称”就是“镜面对称”,“点对称”就是“旋转对称”。 编程中的对称性要比图形中的对称性抽象的多,编程中的对称性是指相同思路的代码在任何地方都以相同的形式表现出来。 简单来说,就是组内的等级整理。同类的东西,也就是拥有相同性质的东西,要用相同的等级来表现。 为什么 在代码中明确表现出对称性后,代码的可读性大幅提高

实现编程理论的六个原则③逻辑与数据的一体化

是什么 逻辑与数据的一体化是指把逻辑和逻辑处理的数据放在相近的位置。 所谓相近的位置,指的是在同一个函数或同一个模块内。距离越近,代码的质量就越高。 为什么 修改代码时往往需要同时修改逻辑与该逻辑处理的数据。 因此,如果把二者放在同一位置,我们要阅读代码就会减少,修改也不会波及其他元素。从结果来看,这么做降低了修改成本。 怎么做 我们要把数据与逻辑放在相近的位置。 不过,我们很难一

实现编程理论的六个原则②重复最少化

是什么 重复最少化,就是指极力消除重复。 许多技术都以实现重复最少化为目标,函数化技术就是其中之一,该技术将重复的逻辑函数化,整合成一段共享代码来使用。 为什么 通过复制、粘贴让同一段代码出现在多个位置时,如果有一个地方进行了修改,我们就必须检查其他地方,判断各处是否需要修改,这个判断很难把握,并不是全部替换就万事大吉了,而且检查时不能只看复制部分,其周围的部分也要检查,只有这么做才能正确

实现编程理论的六个原则①效应局部化

是什么 效应局部化中的“效应“是指修改带来的影响。 效应局部化是指修改带来的影响控制在局部。 效应局部化是一个很重要的原则。围绕该原则产生了许多技术,模块化就是其中之一。模块化技术的目标之一就是让修改模块所带来的影响停留在该模块的内部。 为什么 在效应非局部化的情况下,某处修改会对其他完全不相关的地方造成影响,使修改成本大幅增加。 这是如果我们知道哪些地方受到影响,或许还有救。然而在大

装箱(背包)问题(Packing Problem)

装箱问题也叫背包问题,简单来说,就是把小货物往大箱子里装,要如何才能装得多。个人常见的经历就是“装冰箱”,很有趣的现象就是常常感觉冰箱再也装不下了,但是经过一翻折腾之后又神奇的装下了。   从企业运作角度来看就是尽量让每个容器(仓库、车辆、集装箱、船等)装的尽量多,可以节约企业的费用。通常,装载率85%左右,使用装箱优化方法后,可以达到90~95%左右。海尔做过一个海运装箱的项目,节约了大量运