最新的一个面试的算法题目——一个完全背包问题
2013-08-20 17:29
435 查看
一个集合x有都不相同的n个元素,使用这个集合中的不定个数的元素,组成一个和为s的序列,求出所有符合的序列,元素可以重复使用,只要元素的个数相同不考虑顺序。
比如集合是x={2,3,4,5,7}; n=5, s=12可以得出以下的序列:
2 2 2 2 2 2
2 2 2 3 3
3 3 3 3
2 2 2 2 4
2 3 3 4
2 2 4 4
4 4 4
2 2 3 5
3 4 5
2 5 5
2 3 7
5 7
解题思路:
元素存在arr数组中,大小为size。
path[i][j]表示数组前i个元素(一个元素可出现多次),组成重量恰好为j装入背包的可能,如可能则为true,否则为false。得到递推关系:
path[i][j]=true,if path[i][j-arr[i]]=true的话;否则为false。
边界条件path[i][0]=true(i为1...size),为了避免遍历,在程序中使用hashtable数组,如果可以通过前面的元素组成容量为j的背包,则hashtable[j]=true,否则为false。
求出path数组后,通过printPath(int i,int j,int c)函数打印出所有的路径。printPath(int i,int j,int c)是个递归函数,表示打印出所有第i个元素和前i-1个元素组成容量为j的背包的路径,函数递归过程中使用v队列保存过程中的元素,其中c为v队列的大小。如printPath(2,12,0)将arr[2]=3加入队列,然后调用printPath(2,9,1)将3入队,然后分两路,一路如蓝字所示,调用printPath(1,6,2)将2入队,...,队列中元素为3,3,2,2,2,逆序打印;一路如浅红色所示,调用printPath(2,6,2)将3入队,...,队列中元素3,3,3,3,逆序打印。调用递归函数请读者仔细体会。
比如集合是x={2,3,4,5,7}; n=5, s=12可以得出以下的序列:
2 2 2 2 2 2
2 2 2 3 3
3 3 3 3
2 2 2 2 4
2 3 3 4
2 2 4 4
4 4 4
2 2 3 5
3 4 5
2 5 5
2 3 7
5 7
解题思路:
元素存在arr数组中,大小为size。
path[i][j]表示数组前i个元素(一个元素可出现多次),组成重量恰好为j装入背包的可能,如可能则为true,否则为false。得到递推关系:
path[i][j]=true,if path[i][j-arr[i]]=true的话;否则为false。
边界条件path[i][0]=true(i为1...size),为了避免遍历,在程序中使用hashtable数组,如果可以通过前面的元素组成容量为j的背包,则hashtable[j]=true,否则为false。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | |
1 | T | F | T | T | T | F | T | F | T | F | T | F | T |
2 | T | F | F | T | F | T | T | T | T | T | T | T | T |
3 | T | F | F | F | T | F | T | T | T | T | T | T | T |
4 | T | F | F | F | F | T | F | T | T | T | T | T | T |
5 | T | F | F | F | F | F | F | T | T | T | T | T | T |
#include <stdio.h> #include <stdlib.h> #include <assert.h> #include <string.h> #include <memory.h> #define _DEBUG 1 #define MAXM 20 #define MAXN 10 int arr[MAXN];//数数组 bool path[MAXN][MAXM+1];//路线 bool hashtable[MAXM+1];//是否存在 int c;//记录打印队列大小 int v[MAXM+1];//打印队列,数组大小最大为MAXN+1,此时每个数为1 void printPath(int i,int j,int c){ if(path[i][j] &&j-arr[i]==0){//第一个点 printf("%d ",arr[i]); for(int t=c-1;t>0;t--){ printf("%d ",v[t]); } printf("%d\n",v[0]); return; } assert(path[i][j]); v[c++]=arr[i];//将元素加入到打印队列中 for(int k=1;k<=i;k++){ if(path[k][j-arr[i]]) printPath(k,j-arr[i],c); } c--;//将元素从打印队列中删除 } void solve(int size,int m){//size表示数组的大小,从1开始 int i,j; //初始化 memset(path,false,sizeof(path)); hashtable[0]=true; for(i=1;i<=size;i++){ for(j=arr[i];j<=m;j++){ if(hashtable[j-arr[i]]){ hashtable[j]=true; path[i][j]=true; } } } for(i=1;i<=size;i++){ if(path[i][m]){ printPath(i,m,0); } } } int main(){ #if _DEBUG==1 freopen("interview.in","r",stdin); freopen("interview.out","w",stdout); #endif int n,m; int i,j; scanf("%d %d",&n,&m); for(i=1;i<=n;i++){ scanf("%d",&arr[i]); } solve(n,m); return 0; }
相关文章推荐
- 程序员代码面试指南:IT名企算法与数据结构题目最优解-字符串问题:C/C++语言实现
- [面试算法] 01背包 & 完全背包
- 题目1454:Piggy-Bank 完全背包问题
- 【算法】完全背包问题
- 01背包问题和完全背包问题,一个不理解的关键。
- 经典算法面试题目-判断一个字符串中的字符是否唯一(1.1)
- 经典算法面试题目-判断一个字符串中的字符是否唯一(1.1)
- 经典算法面试题目-翻转一个C风格的字符串(1.2)
- 经典算法面试题目-翻转一个C风格的字符串(1.2)
- 【算法系列学习】[kuangbin带你飞]专题十二 基础DP1 F - Piggy-Bank 【完全背包问题】
- 算法竞赛宝典 动态规划 货币系统问题(完全背包+一维优化)
- 数据结构经典算法学习之完全背包问题
- 算法->完全背包问题 UVa 674 Coin Change
- 这是一个我面试某公司的算法题目:对一个字符数组进行排序,根据给定的字符,大于它的,放在数组的左边,小于它的,放在数组的右边,且数组中的元素之间的相对位置要保持不变。
- 经典算法题05-完全背包问题
- 题目1454:Piggy-Bank(完全背包问题)
- HashMap与Hashtable的区别是面试中经常遇到的一个问题。这个问题看似简单,但如果深究进去,也能了解到不少知识。本文对两者从来源、特性、算法等多个方面进行对比总结。力争多角度、全方位的展示二者的不同,做到此问题的终结版。
- 2015年华为面试用C语言编写一个求大数字阶乘算法的题目
- DP算法入门(2)——完全背包问题(POJ2063题解)
- 一个背包算法问题