程序员笔试题---01背包问题
2017-03-31 16:03
288 查看
引言
前几天笔试网易,题目比华为难度高,但是其实都很常规,主要还是自己练习太少,很多题目都只是粗浅的看过,并没有理解其内涵。比如网易家这道关于双核CPU任务调度的,实际上就是01背包问题,当时记得见过这类问题,但是没有想到是01背包问题,不过就算想到了,我一时也不能马上写出来。因此,现在重新总结01背包问题,避免以后遇到类似问题没有头绪。01背包问题
对于n个重量分别为wj的食物,有一个容量为K的背包,问能否从n个食物中选择一部分将背包完全塞满?(或问背包最多能装走多重的食物?)。可以利用01背包问题解决的类似问题有:如何将一个数组划分为两个数组,且这两个数组的元素和相等?问题分析
假设p(n,K)代表n个食物且背包重量为K的问题的解,那么我们可以将问题分为两种情况:若第n个食物是问题最优解的一部分,则p(n,K)=p(n−1,K−wn)
否则,p(n,K)=p(n−1,K)
这样我们只需要计算所有p(i,k)…k∈[1,K],i∈[0,n]即可。
初始条件容易获得p(i,0)=true…i∈[0,n]p(0,k)=false…k∈[1,K]
也就是说背包容重为0时,总是能够塞满背包;而物品为0且背包容重大于0时,总是不能塞满。
实际代码中,我们可以建立一个大小为n*K的表格记录下所有p(i,k)(如果不需要知道中间过程,可以只使用2*K空间, 也就是两个数组分别存储p(i - 1,k)的数据和p(i,k),每次完成一次记录后交换数组即可。)。如下所示为leetcode中一道类似的题目解答:
leetcode 416. Partition Equal Subset Sum
class Solution { public: bool canPartition(vector<int>& nums) { int sum = accumulate(nums.begin(),nums.end(),0); if(sum&1) return false; sum >>=1; int size= nums.size(); vector<int> col1(sum + 1); vector<int> col2(sum + 1); col1[0] = 1; for(int i = 0;i < size;++i){ for(int k = 0;k <= sum;++k){//根据col1更新col2 if(col1[k])//如果p(i - 1,k) = 1,则p(i,k) = 1 col2[k] = col1[k]; else if(k >=nums[i])//否则p(i,k) = p(i-1,k - nums[i]) col2[k] = col1[k-nums[i]]; } col2.swap(col1);//交换数组 } return col1[sum];//返回p(n,sum) } };
如果问题是问背包中最多能装多少食物。那么p(i,k)的记录就不应该只是简单的true or false 而是k背包能从i个食物中能装的最大值。
... if(k >=nums[i])//如果k能容纳nums[i]则p(i,k)取p(i - 1,k-nums[i])+nums[i] 和 p(i -1,k)的最大值 col2[k] = max(col1[k-nums[i]] + nums[i],col1[k]); else //否则就取 col2[k] = col1[k]; }
相关文章推荐
- ASP.NET程序员笔试最常见问题
- [转]成为嵌入式程序员应知道的0x10个问题——笔试常考
- ASP.NET程序员笔试最常见问题
- ASP.NET程序员笔试最常见问题
- 程序员面试题精选(32):金币概率问题(威盛笔试题)
- 成为嵌入式程序员应知道的0x10个问题——笔试常考
- 程序员笔试常见问题易错点,持续更行中!!!
- C++程序员经常问的11个问题
- 想成为嵌入式程序员应知道的0x10个基本问题
- C++程序员经常问的11个问题
- 应聘Java笔试时可能出现问题及其答案
- 有感:应聘Java笔试时可能出现问题及其答案(第二版Part one)
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
- 嵌入式程序员应知道的10个基本问题
- JAVA程序员必读:---编程中的一些共同的问题
- C++程序员在学习C#时需要注意的一些问题(一)
- 想成为嵌入式程序员应知道的0x10个基本问题
- 微软笔试问题总结,吃一堑长一智
- java程序员面试所被问到的问题?
- C语言测试:想成为嵌入式程序员应知道的0x10个基本问题