回复 34楼 panpende
你的程序在很大固定的数值区间内, 能够迅速精确找到数据.
但是我以 SS=451649.20 代入你的程序,好长数据出不了结果. 是不是陷入死循环,不得而知.
我是在前天才想起了一个小问题.如果设定了一个比表的总和还要大的值,
程序是跳不出死循环的,需要在程序起始的地方对目标值范围进行限定.取值区间是 [和,最小值]
(当然也可以在循环中间判断,但多一句判断就浪费一次循环的速度)
我第一次写的错误代码时,发现循环需要太多时间的时候,我sum了一下,
发现数据表中的总和是451649.22,当时我觉得这和目标值420000的差比较小,
应该使用(451649.22-420000=31649.22)作为目标值,得到的结果,从表中排除就能得到答案了.
(贴上来的代码注释掉了),但各个目标值的速度有不同,是因为它们有不同的位置,
因为我并不懂的太多数据树枝叶之类的理论,所以用的是最原始的办法,应该是叫做"遍历"吧.
至于你说到的这个长时间没反应的问题,我用调试器追踪了一下变量的变化.
程序并没有陷入死循环,而是一直在不同的组合中判断.
因为几乎可以等同于173个循环,所以耗费的时间是巨大的.
使用原目标值420000的时候,大概平均两秒钟出一个答案,(第一个答案当不得结论)
我想计算一下所有可能得到420000结果的方法的个数,
当我算到三万多个结果的时候,电脑死机了,回不到断点,所以没能继续下去.
这个时候,已经花了超过30000*2/3600=16个小时的时间了.
扣除一半的显示时间,乐观估计编译后能快上一倍,可以想像,一两个小时内不可能循环完毕.
所以这个时间,应该使用它们的差(451649.22-451649.20=0.02)作为目标值,
再从前面的限定区间得知,超出范围不能计算,于是可以得知,没有相等的加法算式.
(当然,这就失去了获得近似值的办法,需要加多一次代码进行近似值获取)
其实,遇到这种长时间循环得不到结果的情形下,代码还可以完善的
在总和<目标值,而且达到数据末的时候,
可以顺序回到最后一下连续的序列之前的加法往下序:
例如:.....Y169,Y171,Y172,Y173
判断到 s1<ss,r(k)=N
抛弃后面连续的序号.从最后一个序号往上找,找到一个不连续的序号,往后跳一个,得:
......Y170
由此序列开始往后循环,可以加快一点速度.但于事无补,仍然不可能马上得到答案.
修改代码如下:
ss=451649.20
*USE K:\test.dbf
sum A1 to s0
N=RECCOUNT()
COPY TO ARRAY Y1 FIELDS A1
=ASORT(Y1,1,-1,1)
DIMENSION r(N)
if ss>s0 or ss<Y1(N) then
?"End"
return
endif
k=1
r(k)=1
s1=Y1(r(k))
DO WHILE !(s1=ss)
IF s1>ss THEN
s1=s1-Y1(r(k))
r(k)=r(k)+1
ELSE
IF r(k)=N THEN
FOR i=k TO 2 STEP -1
IF r(i-1)-r(i)=1 THEN
s1=s1-Y1(r(i))
ELSE
EXIT
ENDIF
NEXT
if i=1 and r(1)-r(2)=1 then
?"End"
return
endif
k=i
s1=s1-Y1(r(k))
r(k)=r(k)+1
@5,10 say i
ELSE
k=k+1
r(k)=r(k-1)+1
ENDIF
ENDIF
DO WHILE r(K)>N
IF k=1 THEN
?"End"
RETURN
ENDIF
k=k-1
s1=s1-Y1(r(k))
r(k)=r(k)+1
ENDDO
s1=s1+Y1(r(k))
ENDDO
s2=STR(Y1(r(1)),10,2)
FOR i=2 TO k
s2=s2+"+"+STR(Y1(r(i)),10,2)
NEXT
s2=STRTRAN(s2+"="+STR(EVALUATE(s2),10,2)," ","")
?s2