| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 6728 人关注过本帖
标题:请教怎样在多数据中快速选择出几个数值合并成一个固定的数值?
只看楼主 加入收藏
软件服务
Rank: 8Rank: 8
等 级:蝙蝠侠
威 望:3
帖 子:344
专家分:736
注 册:2011-12-23
收藏
得分:0 
可惜我的是商业,就不参与你们的代码展现
2011-12-28 19:55
panpende
Rank: 8Rank: 8
等 级:蝙蝠侠
威 望:4
帖 子:528
专家分:963
注 册:2009-4-27
收藏
得分:0 
向Moz高手学习.
2011-12-29 13:43
tlliqi
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:204
帖 子:15453
专家分:65956
注 册:2006-4-27
收藏
得分:0 
相互学习 共同提高
2011-12-29 16:36
panpende
Rank: 8Rank: 8
等 级:蝙蝠侠
威 望:4
帖 子:528
专家分:963
注 册:2009-4-27
收藏
得分:0 
楼主的TEST表中的173个数据,好神奇,可以组合成相当多的连续数。
2011-12-31 15:33
Moz
Rank: 1
等 级:新手上路
帖 子:8
专家分:0
注 册:2007-5-27
收藏
得分:0 
回复 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
2012-01-01 11:49
Moz
Rank: 1
等 级:新手上路
帖 子:8
专家分:0
注 册:2007-5-27
收藏
得分:0 
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
            if r(i-1)-r(i)=2 then           &&多加了这一段,是因为换一个更小的数,不会大于上一个序列.

                FOR i=i-1 TO 2 STEP -1
                    IF r(i-1)-r(i)=1 THEN
                        s1=s1-Y1(r(i))
                    ELSE
                        EXIT
                    ENDIF
                NEXT
            endif
            k=i
            s1=s1-Y1(r(k))
            r(k)=r(k)+1
        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

[ 本帖最后由 Moz 于 2012-1-1 15:16 编辑 ]
2012-01-01 11:57
Moz
Rank: 1
等 级:新手上路
帖 子:8
专家分:0
注 册:2007-5-27
收藏
得分:0 
不好意思,忘了.

新年快乐.
2012-01-01 12:03
panpende
Rank: 8Rank: 8
等 级:蝙蝠侠
威 望:4
帖 子:528
专家分:963
注 册:2009-4-27
收藏
得分:0 
谢谢Moz老师的分析、指教,你的思路使我受益匪浅。

执行36楼的程序发生错误。位置是  if r(i)-r(i+1)=2 then           &&多加了这一段,是因为换一个更小的数,不会大于上一个序列.

并且在执行29楼的程序,在调试器追踪时发现:有数组超范围的现象, r(k)的最大值=175  ,但是出现 r(k)=176  
祝新年快乐。
2012-01-01 14:25
Moz
Rank: 1
等 级:新手上路
帖 子:8
专家分:0
注 册:2007-5-27
收藏
得分:0 
我把代码作了些许修改,这次只是凭空想像的,没有实际运行过,也许还会有错.
对于不同的情形,我觉得还是用不同的代码进行处理比较好,甚至可以尝试动态代码,
(类似于C的什么动态入口重载之类的,我其实不懂的.)
(VFP对于VB有好多优点,它甚至可以运行实时产生的代码,还可以测试不存在的变量和属性.)
庞大的循环体里面,即使是简单的判断语句,如果不能达到事半功倍的捷径跳跃效果,就会成为额外的负担.


哦,不要叫我老师,我不是老师,也不是专业人士,更不是专家.纯粹业余爱好.
青春一去不复返.我更希望别人叫我小Moz,我好显年轻一点.

[ 本帖最后由 Moz 于 2012-1-1 15:46 编辑 ]
2012-01-01 15:35
panpende
Rank: 8Rank: 8
等 级:蝙蝠侠
威 望:4
帖 子:528
专家分:963
注 册:2009-4-27
收藏
得分:0 
对于不同的情形,我觉得还是用不同的代码进行处理比较好,甚至可以尝试动态代码.

说得好,尤其是这个例题,或这类例题。
2012-01-02 07:48
快速回复:请教怎样在多数据中快速选择出几个数值合并成一个固定的数值?
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.018371 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved