有一个浮点数字序列,例如下:
344
46
567
35.5
4564
456
3457
98
898
878.89
78
978
问题:有一个数值入2345,求上面的数列中选哪几个相加的值最近于该值?
太难了
我想了半天想不通,请高手指点!!
344
46
567
35.5
4564
456
3457
98
898
878.89
78
978
问题:有一个数值入2345,求上面的数列中选哪几个相加的值最近于该值?
太难了
我想了半天想不通,请高手指点!!
Form1: TForm1;
myarr:array[1..12] of double=(344,
46,
567,
35.5,
4564,
456,
3457,
98,
898,
878.89,
78,
978);
implementation{$R *.dfm}
function Cha(x,y:double):double;
begin
if x>=y then result:=x-y else result:=y-x;
end;function GetNearNum(n:double):double;
var i:integer;d:double;
begin
d:=cha(n,myarr[1]);
for i:=1 to 12 do
if cha(n,myarr[i])<d then
begin
d:=cha(n,myarr[i]);
result:=myarr[i];
end;
end;procedure TForm1.Button1Click(Sender: TObject);
begin
showmessage('最接近值为:'+floattostr(GetNearNum(2345)));
end;
讲个大概的算法:;
1.从n个数里取m个数组合,m=n直到m=1(要用到递归).
2.得出组合后,对每个组合相加和目标数求差,对该差值和该组合建立关系
3.对差值排序得到最小值,通过该最小值找到组合
重点和难点是得到组合序列.
可以采用便宜算法,规定差值在某个范围即表示找到.然后每取到一个组合就比较,只要符合就返回退出,这样不用把所有的组合都枚举出来.
取数组合的算法,可以从m=1...n开始也可以从m=n...1开始.
讲个大概的算法:;
1.从n个数里取m个数组合,m=n直到m=1(要用到递归).
2.得出组合后,对每个组合相加和目标数求差,对该差值和该组合建立关系
3.对差值排序得到最小值,通过该最小值找到组合
重点和难点是得到组合序列.
可以采用便宜算法,规定差值在某个范围即表示找到.然后每取到一个组合就比较,只要符合就返回退出,这样不用把所有的组合都枚举出来.
取数组合的算法,可以从m=1...n开始也可以从m=n...1开始.不要划一个范围吧,每次记录计算过的差值最小的就可以了。
344,
46,
567,
35.5,
4564, 456,
3457,
98,
898,
878.89,
78,
978);
procedure TForm1.btn1Click(Sender: TObject);
begin
Combination(myarr, 2345, 10000);//2345是相加逼近值,10000是给出一个最初的相差
end;function Combination(mArry: array of double; mCon: double; mCha: double): Boolean; //mArry初始数组,
var
nilArray: array of double; procedure fCombination(mLeft, mRight: array of double);
var
i, j, k, l: Integer;
sRight: array of double;
sLeft: array of double;
sumTemp: double;
temStr: string;
begin
if Length(mLeft) >= 1 then
begin
sumTemp := 0;
for i := 0 to Length(mLeft) - 1 do
begin temStr := temStr + FloatToStr(mLeft[i]) + ',';
sumTemp := sumTemp + mLeft[i];
end;
if Abs(mCon - sumTemp) < mCha then
begin
mCha := Abs(mCon - sumTemp);
Form1.mmo1.Lines.Add(temStr);
Form1.mmo1.Lines.Add(FloatToStr(mCha));
Form1.mmo1.Lines.Add(#13);
end;
end; for i := 0 to Length(mRight) - 1 do
begin
j := Length(mLeft);
setlength(sLeft, j + 1);
for j := 0 to Length(mLeft) - 1 do
sLeft[j] := mLeft[j]; sLeft[Length(sLeft) - 1] := mRight[i]; setlength(sRight, Length(mRight) - i - 1); for k := 0 to Length(mRight) - i - 2 do
sRight[k] := mRight[k + 1]; fCombination(sLeft, sRight); end;
end;begin
result := False;
try
fCombination(nilArray, myarr);
finally end;
result := True;
end;这个递归有点问题,会出现重复值,大家看着帮忙修正吧。
begin
Combination(myarr, 12345, 100000);
end;function Combination(mArry: array of single; mCon: single; mCha: single): Boolean; { 组合 }
var
nilArray: array of single; procedure fCombination(mLeft, mRight: array of single);
var
i, j, k, l: Integer;
sRight: array of single;
sLeft: array of single;
sumTemp: single;
temStr: string;
begin
if Length(mLeft) >= 1 then
begin
sumTemp := 0;
for i := 0 to Length(mLeft) - 1 do
begin
temStr := temStr + FloatToStr(mLeft[i]) + ',';
sumTemp := sumTemp + mLeft[i];
end;
if Abs(mCon - sumTemp) < mCha then
begin
mCha := Abs(mCon - sumTemp);
Form1.mmo1.Lines.Add(temStr);
Form1.mmo1.Lines.Add(FloatToStr(mCha));
Form1.mmo1.Lines.Add(#13);
end;
end; for i := 0 to Length(mRight) - 1 do
begin
j := Length(mLeft);
setlength(sLeft, j + 1);
for j := 0 to Length(mLeft) - 1 do
sLeft[j] := mLeft[j]; sLeft[Length(sLeft) - 1] := mRight[i]; setlength(sRight, Length(mRight) - i - 1); for k := i to Length(mRight) - 2 do
sRight[k - i] := mRight[k + 1]; fCombination(sLeft, sRight); end;
end;begin
result := False;
try
fCombination(nilArray, myarr);
finally end;
result := True;
end;
貌似这样就好了。你们仔细看看吧
344,46,98,878.890014648438,978,
0.10986328125 小数点位数问题是因为double和single数据类型的问题。real应该就没有这个问题了。878.890014648438就是878.89