子集和问题的问题描述
对于一个正整数的集合S和一个给定的正整数C,求出S的一个子集,使得该子集中的元素之和小于C并且S不存在另一个子集元素之和小于C且比S中的元素之和要大。
子集和问题近似算法的伪代码描述
输入:正整数集合S,正整数C,近似参数a;
输出:小于C的最大和数
1.初始化:L[0]={0};b=a/n(n为S中元素的个数)
2.循环变量i从1-n依次处理集合S中的每一个元素s[i]:
2.1.计算L[i-1]+s[i];
2.2.递推计算:L[i]=L[i-1]∪(L[i-1]+s[i])
2.3.在Li中删除所有比C大的元素
2.4.对Li中的每一个元素z,删除与z相差范围在b之内的元素
3.输出L[n]中的最大元素。
子集和问题的算法实例分析
设近似参数a=0.5,且S={10,11,12,15,20},C=40,求最大子集和。
①L[0]={0},b=a/n=0.5/5=0.1。
②L[1]=L[0]∪(L[0]+S[0])={0}∪{10}={0,10};
③L[2]=L[1]∪(L[1]+S[1])={0,10}∪{11,21}={0,10,11,21};
由于11*(1-0.1)=9.9<10<11,因此从L[2]中删除10,修正为{0,11,21}。④L[3]=L[2]∪(L[2]+S[2])={0,11,21}∪{12,23,33}={0,11,12,21,23,33};
由于12*(1-0.1)=10.8<11<12,因此从L[3]中删除11;同理由于23*(1-0.1)=20.7<21<23,因此从L[3]中删除21。修正后的L3={0,12,23,33}。
⑤L[4]=L[3]∪(L[3]+S[3])={0,12,23,33}∪{15,27,42,48}={0,12,15,27,33,34,42,48}。 删除比40大的元素,将L[4]修正为{0,12,15,27,33,34};
由于34*(1-0.1)<33<34,因此删除33,将L[4]进一步修正为{0,12,15,27,34}。
⑥L[5]=L[4]∪(L[4]+s[4])={0,12,15,27,34}∪{20,32,35,47,54}={0,12,15,20,27,32,34,35,47,54}。
删除比40大的元素,将L[5]修正为{0,12,15,20,27,32,34,35};
由于34*(1-0.1)<32<34,因此删除32;同理由于35*(1-0.1)<34<35,因此删除34;
经过上述修正后L[5]={0,12,15,20,27,35}。 到此为止问题求解完成,近似最优解为35。
算法的时间复杂度和相对误差
子集和问题的算法时间复杂度为O(n*L[n]中的元素个数)。算法的相对误差不会超过a。