北京 | 上海 | 天津 | 重庆 | 广州 | 深圳 | 珠海 | 汕头 | 佛山 | 中山 | 东莞 | 南京 | 苏州 | 无锡 | 常州 | 南通 | 扬州 | 徐州 | 杭州 | 温州 | 宁波 | 台州 | 福州 | 厦门 | 泉州 | 龙岩 | 合肥 | 芜湖 | 成都 | 遂宁 | 长沙 | 株洲 | 湘潭 | 武汉 | 南昌 | 济南 | 青岛 | 烟台 | 潍坊 | 淄博 | 济宁 | 太原 | 郑州 | 石家庄 | 保定 | 唐山 | 西安 | 大连 | 沈阳 | 长春 | 昆明 | 兰州 | 哈尔滨 | 佳木斯 | 南宁 | 桂林 | 海口 | 贵阳 | 西宁 | 乌鲁木齐 | 包头 |
有一组数。
任意给出一个数,求该数能否是数组中几个数的和。是的话给出答案,如果有几个的话只要一个就行。
用循环枚举组合,当其和达到预设值时跳出循环即可。
数组中有无负值?有无重复?
没有负值的话,可以先把大于所给数的部分数字去掉,其它的用穷举法
1 你的数据是从1到20的连续数,如果你的数据就是从1到n的连续数,那你的算法就太复杂了
2 如果数组中的数是随机的,并且可以有重复,可以有负数,那么你只能穷举。
3 如果数组中的数是随机的,但只能正数,那么你可以做些简化。
如果是1的情况,那么求出数组的总和,如果小于所给数,那么无解;如果等于所给数,那么只有一个解;如果大于所给数,那么数组中 除了( 数组之和-所给数 )之外的其它数就构成1个解。
如果是2的情况,可以利用上面1的处理方法,事先做些判断。首先,数组中所有正数之和如果小于所给数,则无解;如果所有正数之和等于所给数,有一个解;如果所有正数之和大于所给数,那就把负数算上,一个个加起来试。
3的情况,又需要分为两种,一种是有重复数字,一种是没有重复数字。有重复数字的,穷举。没有重复数字的,可以求出数组总和,如果小于所给数,则无解;如果等于所给数则有一个解;如果大于所给数,穷举
这是穷举递归算法,没有加任何智能的
Option Compare Database
Const showProcess = False
Sub aaa(testNum, st)
Dim src, tgt
src = Split(st, ",")
ReDim tgt(UBound(src))
Debug.Print "含 " & UBound(src) & " 个元素的数组"
v = Timer()
Debug.Print v
For i = 1 To UBound(src) + 1
If gogo(src, i, 0, tgt, 0, 0, testNum) Then Exit For
Next
q = Timer()
Debug.Print q
Debug.Print "耗用时间为: "; Timer() - v; "ms"
End Sub
Function gogo(src, qty, stt, tgt, tgtLen, tgtSum, testNum)
gogo = False
If qty = 1 Then
For i = stt To UBound(src)
ss = tgtSum + src(i)
tgt(tgtLen) = i
If showProcess Or ss = testNum Then
For z = 0 To tgtLen: Debug.Print "+"; tgt(z);: Next
Debug.Print , "sum:", ss
End If
If ss = testNum Then gogo = True: Exit Function
Next
ElseIf qty + stt = UBound(src) + 1 Then
ss = tgtSum
If showProcess Or ss = testNum Then
tl = tgtLen
For i = stt To UBound(src)
ss = ss + src(i)
tgt(tl) = i
tl = tl + 1
Next
For z = 0 To tl - 1: Debug.Print "+"; tgt(z);: Next
Debug.Print , "sum:", ss
End If
If ss = testNum Then gogo = True
Exit Function
Else
nextqty = qty - 1
For i = stt To UBound(src) - nextqty
tgt(tgtLen) = i
nexts = tgtSum + src(i)
nextqty = qty - 1
gogo = gogo(src, nextqty, i + 1, tgt, tgtLen + 1, nexts, testNum)
If gogo Then Exit Function
Next
End If
End Function
执行结果:
aaa 325, "1,26,26,24,25,31,35,34,5,6,7,7,43,3,4,4,3,34,4,5,6,3,4,65,23,53,2,53,7,23,56,7,1,43,67,3,5,4,6,15,65,48,13,987,15,68,98,48,15,68,48,98,48,15,15,48,98,48,15,46,65,44,84,64"
含 63 个元素的数组
1151.416
+ 5 + 46 + 51 + 56 sum: 325
1151.785
耗用时间为: .3719482 ms
aaa 264, "1,26,26,24,25,31,35,34,5,6,7,7,43,3,4,4,3,34,4,5,6,3,4,65,23,53,2,53,7,23,56,7,1,43,67,3,5,4,6,15,65,48,13,987,15,68,98,48,15,68,48,98,48,15,15,48,98,48,15,46,65,44,84,64"
含 63 个元素的数组
1262.097
+ 45 + 46 + 51 sum: 264
1262.164
耗用时间为: 6.994629E-02 ms
看你怎么应用了,如果要数字是需要很多个数字加总的话,
1. 加入源数字的排序
2. 判断是否有负数
3. 是否全部加总都不够大
4. 最大最小数总和测试
5. 优化计算,先做数字分析以最大,亦近似的数递归下来
6. 优化计算,判断以多少个 最适合大小范围的数字 作预算
“应用数学”一定比“纯数学”来得更有参照性的。
真奇怪,版主的程序我拿来运行了5分钟没有结果。可能电脑落伍了吧。我再给大家传上我后来做的阶段结果以及他的真正应用,由于在调试阶段,代码可能不太好看。如果谁有好的方法,别忘了告诉我一下。谢谢
点击下载此附件
看了你的界面,好像是开料应用!不过不好意思的,看不懂你是在算什么。
1. 看似,凭成品找材料批号;又似,材料批号找可以投产哪个成品;
2. 精度也不懂,50,100,500,1000? 要以1来除的话,干嘛不直接输入小数位? 0.2,0.1,0.02,0.01 ?
3. 结果也看不懂, 成品3000的,原材料4694的,使用率居然是99.77的? 真的难以理解!
不过,不是投诉,只是知道你是一个粗略版本,根本还需要很久才成型的!
我猜想,这是有点真实的数据的话:
1. 如果你是一张材料的话,一定需要长和宽的;所以否决!
2. 看你原材料的表,2000 到 24000 都有,不像 硬的材料,钢、木、等最大只是 2.4米 或者 6米, 12米的样子;
3. 因为看不到你的 成品和材料之间的关系,也猜不透是什么成品!
我只知道,
第一:任何行业,对于成品也会有 最小和最大的限制的,
因为生产过程中的设备和人力都处理不了太大的;太小的会浪费时间;
所以这里一定能作一个优化的;
第二:即使你么你是卖原材料的话,成品就会是 数量少、规格多的了!
但是同一个行业也不会切 几毫米的东西,同时也要计算 几十米的材料的。
所以我说的纯数学是不存在的,譬如用10000个 10毫米左右的东西来开 2.4米的材料,因为是不实际的!
在应用数学里面 范围就小很多,能优化计算的条件就可以更多了!
看了你的样板,都没有看出你要算的是什么!所以没办法帮到你!
我上面穷举计算,要算100个数字的都可以的,时间一定会慢的了,如果你记得初中的 机会率中的 nCr 是什么的话,
你就知道这个穷举就是 C100, 0 到 C100,100 的可能性 的总和,应该就是 2^100 -3 个可能性,不过我代码我测试过 C10,0 - C10,10 绝对没错的了!
等不等到答案就看你用多少台电脑了!
当然,说到真实应用,那个代码是不能接受的!哪有什么智能计算的软件要算几天的?
1995年我就用 Access 做了 PCB 开料计算;也只是用 P5-166Mhz 64M 内存的电脑,还是 1秒里面算出了所有的可能性的了,至今已经超过500用户;
1998年也是用 Access 为啤酒厂家计算一个货柜怎么塞叠货箱、或者塞叠圆桶的计算,也是1秒时间里面出来的;
今年开发的 Flash 应用,也是在一个行车货场内提取一车货物,提供一条最优的行车路线,都是一秒里面要出来的!
其实,你想执行快的话,只需要知道计算逻辑,然后节省计算循环反而是最关键的!
记得:杀鸡别用牛刀,意思是,算使用率的话,就别计算大部分是使用率1%大小的需求;因为订单都是1%大小的话,怎么算开料的话,一定是99%的,有99个订单以上就可以了!
我们的任务就是对材料的需求是 3% 到 33% 大的时候电脑程序才显得有价值的。
我这个是准备用光缆上面的,所以只有长度。
利用率是指原材料的利用率:例子里面 成品 x2长度3000,x12长度1683,原材料:ycl000028长度4694. 利用率=(3000+1683)/4694
怎么样在生产成品时找到合适的原材料是本程序的关键(利用率越高越好,计算时间越短越好)
果然,不是硬的,是软的!规格多、数量少的材料品种。呵呵,那就明确了!
1. 光缆原长度是多少? (最大值)
2. 设置 最短的处理需求。概念是:
a) 2000M 的 不应该切来给 1000M的需求吧?尽管有两个需求1000Km 使用刚好事100%
b) 又或者 2M的需求应该任意 切吧? 设个 譬如3% 以下可以任意切之类
c) 也为原材料 定下可不可以切的属性
d) 多长后,最大分段数。譬如5km 后就不分割,或者最多分两段
4. 还有需求时间问题,可以不做考虑,意思是要不要多等几天到要交货日期才决定从哪一根碎料里面切出来,
反正“急”交货,损耗率高也得 切!
还有,就是象棋的多少步后的 评估问题。我详细说明下吧:
你手头上有 m个需求, 有 n段碎料,
你这个初步的算法是 每段碎料找合适的组合,
但是你知不知道,当你从 n段碎料里面拿的顺序不一样会造成,整体的损耗率的区别?
所以这就是 要算 哪一根碎料先处理、然后哪根、然后再哪根 的问题了!
这就是象棋软件里面对 这一步的评分 是根据 后面几十步的评分的总和来 打分的;
当然 后面的几十步里 也有各自的树杈 评分情况的。
你想这个系统有多复杂?或者有多快?
可能今天突然来个需求单,你整盘计划也会有颠覆性的变化的。
在没有那么复杂以前,你只是想看看各个需求加总的情况的话,其实我还有多两个运算更快的方案给你的!
一个最影响你这个运算速度的,就是你要判断出,最大可以分多少段来组合!
想想看,一根2KM的光缆,切给5条200M 是否值得? 200M 哪里切出来不可以?干嘛浪费一根2KM 的呢?
所以这个规则就要先弄清的。
当你能确定 最多段数、最小切割长度、最小切割比例 所有机计算就会缩得很小的了!
用空间换取时间的两个方法:
1. 耗用内存: 把需求放到SQL引擎处理,适合最高3段组合,需求100个也无所谓的,因为生成的记录数 只在100x100x100+100*100+100 条记录
select x1.长度+x2.长度+x3.长度 from 需求 as x1, 需求 as x2, 需求 as x3 where x1.id<>x2.id and x2.id<>x3.id
就能穷举 3段加总的所有长度的了。
你内存够大,就可以计算更多的需求,及更多的组合。
2. 使用超大的硬盘:(适合3段以上的应用)
把我上面的代码 与处理成 关联数据表 c1,1 到 c100,100 的 会过分的多, 到 c50,5 就好了
因为你把一根光缆 切 5段 也已经太浪费的了!
记录数就将会是 20630574 条,能处理从 50个需求中 取 1-5段的总和
生成了组合的预处理,你以后 一关联查询,+ sum( 长度)就得出所有组合的 总长的了!
如果你真的耗尽硬盘来计算的话 C100,5 也只是 1350803394条记录,Access 还是支持的!
但是 C100,6 就18550416594条记录,溢出了! 不过还是可以用计算的方式来慢慢算的!
你原来的题目只是笼统的用“数组”,也没有提出限制,那就只能 提供给你我的 VBA Combination 穷举代码了。
等你判别好 那些限制后,再决定用什么方法吧!
咖啡兄,那个Excel能做的效果,上面的代码已经实现的了!
aaa 18, "25,22,9,50,5,6,7,8,15,10"
含 9 个元素的数组
+ 7 + 9 sum: 18
+ 4 + 5 + 6 sum: 18
耗用时间为: .015625 s
aaa 18, "25,22,9,50,5,6,7,8,15,10"
含 9 个元素的数组
+ 7 + 9 sum: 18
+ 4 + 5 + 6 sum: 18
耗用时间为: .015625 s
aaa 23, "25,22,9,50,5,6,7,8,15,10"
含 9 个元素的数组
+ 7 + 8 sum: 23
+ 2 + 5 + 7 sum: 23
+ 4 + 7 + 9 sum: 23
+ 5 + 6 + 9 sum: 23
耗用时间为: 2.734375E-02 s
aaa 100, "25,22,9,50,5,6,7,8,15,10"
含 9 个元素的数组
+ 0 + 3 + 8 + 9 sum: 100
+ 0 + 2 + 3 + 5 + 9 sum: 100
+ 0 + 3 + 6 + 7 + 9 sum: 100
+ 1 + 3 + 4 + 7 + 8 sum: 100
+ 1 + 3 + 5 + 6 + 8 sum: 100
耗用时间为: 6.640625E-02 s
此帖发展到今天,已经不是加数等于 某一个数的问题了!
是 希望能处理 100个 需求数字,
供应数字 有 一堆,
找最少浪费的 供求配对方案(假设是规格要求一样的东西,)。
如
供的是 16,17,18
求的是 8,8,9,10
能回答出是: 16保留, 17供8+9, 18供9+10
供的是 10,12,14,18,49
求的是 8,10,13,17
配对的是: 10供8废2, 12供10废2, 12供13废1, 18供17废1, 这方案共废6
或者是: 10,12,14,18保留,49供8+10+13+17 废1,这方案总废1
实际情况是没有整数的,是找最接近数,而且基本上相等的几率是接近 0 的。
只是他还没有告诉我
- 什么情况 选大供应保留小的,
- 什么情况不取最小供应的,
- 什么时候列出所有等值 及 不同分值的 n个 方案让用户选择。
其实要求很简单,就是怎么样用最小的损耗切出成品就行。
现在问题是原材料最长的有50km,成品最短的只有1km,就是说原材料只有50km的时候,如果要切100根1km的成品的话,计算时需要用到C50,50。不是版主所说用到C50,5就行了。由于需要切的数量很多,而不是我例子上面的15根。难题就出来了,怎么样用最短的时间找出最佳组合来。
我明白是需要最少损耗呀,但是还有些碎料(前几次开剩下来的),使用时总有些逻辑的哦!
如
例子A:
供的(存在的碎料)是 16,17,18
求的(现在需要的)是 8,8,9,10
能回答出是: 16保留, 17供8+9, 18供9+10
另一例B:
供的(仓存碎料)是 10,12,14,18,49
求的(需要切的)是 8,10,13,17
配对的是: 10供8废2, 12供10废2, 12供13废1, 18供17废1, 这方案共废6
或者是: 10,12,14,18保留,49供8+10+13+17 废1,这方案总废1
当碎料长度很多种时(超过20种),需求也会是有十个八个时候,这个逻辑就要清楚了。先决定逻辑,才决定算法的!
- 开多少段不是问题的!
- 是否先用最短的碎料?
- 使用短的碎料造成更大的损耗时候呢? 上面两个例子,例A是取较长的;而例B 是取 49的 开4段,还是 拿四段短的,使用损耗更高的?
- 还有 价值问题!如果没有达到95% 使用率的话就开新的50KM 去切吗?
最多你又能开多少条个50KM当存货?(不知道存货跟你的工作有没关系呢?但是整个企业就要考虑的了)
- 综合以上问题,是否该列出多个方案,让人判断?(至少光缆是可以熔接的,有时候必须时也是一个不错的选择)
- 列出的多个又该列什么?
以纯计算角度看你这个事情的话,穷举吧,所有原材料,以每套顺序作为一个方案,去穷举尝试切就好了,等等看算多久吧!
100个不同长度的需求当中,随机取 5条 出来看总长度就有 75287520 个组合了!
不过你说 只有50KM,最少切1KM的话, 那就 最多50段,50个长度需求取10个长度出来 就有 10272278170个组合,
还有 取9条 250543370,取8条 536878650,取7条99884400 ...... 慢慢等吧!
一根50KM原材料,真的要算50个需求,分别在 1.0-1.5公里需求的 所有排列方式,最后剩 600M时,希望可以经过计算剩 100M以下?
还是,不管里面怎么切,最后留下5KM 或者 2.5KM (即10%或5%)下次用就好了?
如果你还没有什么信息怎么收窄范围的话,还是慢慢等计算结果就好了!
谢谢版主的关心。对于企业来说,最关心的还是损耗,一般来说,损耗率在1%左右,由于客户的需求一般不少于1km,所以在生产的过程中是不允许出现切剩几百米的情况的,就算是100米,那也是好长的一段了。想想刘翔都跑不到呢,何况企业。
由于每天的生产量比较大,就需要有一定的存货来保证生产。这个倒不是问题。当然还是需要怎么尽量来减少的。做这个程序也就这个目的。
对于生产企业来说,光缆是不允许熔接的。
想想每天要生产几十、上百根光缆,怎么找到合适的原材料,还真是一个头痛的问题。
Access软件网 版权所有 CopyRight 2006-2030
上海盟威软件有限公司 提供支持
沪ICP备12024966号-4