下面代码中,我不用相等作为约束条件是因为相等这个条件太严格,那个2552328.96本来也是四舍五入了的结果,计算的还有累加和后小数点应该也很多。
clc,clear all
%{
程序的设计思路是:
第一层循环:从35个数里面挑选n个数,n是从1到35的整数。
(这里面有一个技巧,把这35个数从小到大排列,然后从最小的数开始一个一个往上加,
可以发现加出目标数最少需要几个数;同样,从大到小一个一个加,可以发现加出目标数最多需要几个数,这样可以减少循环次数)
然后用b=combntns(a,i)函数找出在数组a中取出i个数的全部组合,求出的b是一个矩阵,每一行记录了一种i个数的组合。
第二层循环:用nchoosek(n,i)算出n个数中取i个数的组合有几种,在刚才算出的b矩阵中每一行分别与其和的误差计算,选取最小误差保存。
如果当前的i个数的组合均不能满足要求,则将i加一,继续考察i+1个数的组合情况
%}
load('data.mat')
% D = [2552328.96,12031346.27];
% L_D = length(D);
data=[3,2,1,5,4]';
D = [6,10];
L_D = length(D);
a=sort(data); %输入35个数,并自动从小到大排列
L_a = length(data);
result={};
for i=1:L_D
result_i = {};
dest=D(i) ; %定义目标数x
%记录从小到大的和与从大到小的和
suma=[0 0];
%初始化加出目标数最多和最少需要几个数
nmax=0;
nmin=0;
for j=1:L_a
suma=[suma(1)+a(j) suma(2)+a(L_a+1-j)];
if nmax==0 && suma(1)>=dest
nmax=j;
end
if nmin==0 && suma(2)>=dest
nmin=j;
end
% 确定好后退出循环
if nmax>0 && nmin>0
break
end
end
num=0;
%把所有数字从大到小排列,发现至少要nmin个数,至多用nmax个数相加可以得到你要的数
% for k=nmin:nmax
for k=5:L_a
%矩阵b存储数组a中i个数的所有组合,一种组合存一行
b=combntns(a,k);
%length(b)=nchoosek(n,k)代表在n个数中取k个的组合数n!/((n–k)! k!)
min_E=Inf;
min_E_n=-1;
L_b=size(b)
for n=1:L_b(1)
c=sum(b(n,:));
%当找到符合条件的组合时,在主界面显示
if abs(c-dest)<min_E
min_E = abs(c-dest);
min_E_n=n;
end
end
% if min_E>5
% continue
% end
num = num+1;
% 序号存储
temp=[];
for m=1:length(b(min_E_n,:))
temp(m)=find(data==b(min_E_n,m));
end
result_i{num}={k,min_E,sort(temp)};
% 画图
plot(k,min_E,'*')
pause(0.1)
hold on
end
result{i}=result_i;
hold off
end
结果说明:假设从35个数中不重合的取出3个数,有6123种排列(二项式)。把每一种排列的累加和分别于目标和做差,找到最小的差值误差为0.98,假设它是由序号[1,4,6]这3个数累加的结果,其中序号1,4,6表示35个数据中第1,4,6个元素。