免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3890 | 回复: 6
打印 上一主题 下一主题

数组处理效率问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-09-12 17:02 |只看该作者 |倒序浏览
a和b数组元素互换,交换后a数组相加值和b数组相加值为组合最小值

下面是我网上借鉴的代码,不过基本没有什么效率,大家能看出哪出了问题不?

新写一个也行?


# -*- coding: cp936 -*-
def  minus(total):
    n = len(total)/2
    a = total[:n]
    b = total[n:]
    return abs(sum(a) - sum(b)),a,b

def func(total,k):
    mi,am,bm = minus(total)
    global minSN,an,bn
    if mi< minSN:
        minSN = mi
        an,bn = am,bm
    for i in range(k,len(total)):
        total[k],total[i] = total[i],total[k]
        func(total,k+1)
        total[k],total[i] = total[i],total[k]   
   
if __name__ == '__main__':
    a = [1,2,3,4]
    b = [6,7,8,9]
    an,bn = a[:],b[:]
    total = a + b
    minSN,am,bm = minus(total)
    func(total,0)
    print an
    print bn
    print  minSN

论坛徽章:
0
2 [报告]
发表于 2012-09-12 18:59 |只看该作者
本帖最后由 Hadron74 于 2012-09-12 19:11 编辑

回复 1# zp307300084

这个疑似是我以前贴的一个程序,呵呵!

现在我有了一个更好的方法,用0-1背包问题来解决这个问题。思路是,给一个总和长的select数组,记录a/b的状态,True表示在a中,False表示在b中。
用递归遍历所有选取n个元素在a中的可能,就遍历了所有可能的交换。这个算法的复杂度小于O(2^(2n)).

其算法可以参考http://www.cnblogs.com/Myhsg/archive/2009/08/29/1556460.html

下面是代码
  1. def  minus():
  2.     global total,select,number
  3.     a = [ total[i] for i in range(number) if select[i] ]
  4.     b = [ total[i] for i in range(number) if not select[i] ]
  5.     return abs(sum(a) - sum(b)),a,b

  6. def func(sumN,k):
  7.     global select,number,halfnumber,minSN,an,bn
  8.     if k==number:
  9.         return
  10.     if sumN == halfnumber:
  11.         mi,am,bm = minus()
  12.         if mi< minSN:
  13.             minSN = mi
  14.             an,bn = am,bm
  15.         return
  16.     select[k] = True
  17.     func(sumN+1,k+1)
  18.     select[k] = False
  19.     func(sumN,k+1)
  20.    
  21. if __name__ == '__main__':
  22.     a = [1,2,3,4]
  23.     b = [6,7,8,9]
  24.     total = a + b
  25.     an, bn = a[:], b[:]
  26.     minSN = abs(sum(a)-sum(b))
  27.     number = len(total)
  28.     halfnumber = number/2

  29.     select = map(lambda x: False,total)

  30.     func(0,0)

  31.     print minSN
  32.     print an
  33.     print bn
复制代码
结果:
  1. 0
  2. [1, 4, 7, 8]
  3. [2, 3, 6, 9]
复制代码

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
3 [报告]
发表于 2012-09-12 19:17 |只看该作者
这是《编程之美》上的DP问题,思路非常新颖。

DP的两个维度分别是sum和num_of_elems_in_set.

论坛徽章:
0
4 [报告]
发表于 2012-09-12 19:21 |只看该作者
回复 3# linux_c_py_php

没有这本书,你能不能贴个程序上来,大家看看。谢谢!


   

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
5 [报告]
发表于 2012-09-12 20:00 |只看该作者
别让我写算法了, 放下好久了.

DP原理: bool dp[sum][num]; 表示num个数字能否加和等于sum. 实现是外层依次遍历所有元素, 将每个元素将入到之前的dp组合考虑中, 很像Floyd的三层循环DP, 可以体会一下.

编程之美里的讲解是逐层深入的, 先从普通的递推枚举方法, 最后演变到DP, 以前上学时读的书, 启发是蛮大的.

Hadron74 发表于 2012-09-12 19:21
回复 3# linux_c_py_php

没有这本书,你能不能贴个程序上来,大家看看。谢谢!

论坛徽章:
0
6 [报告]
发表于 2012-09-17 00:20 |只看该作者
回复 5# linux_c_py_php


    回复 3# linux_c_py_php

谢谢你的建议的书,我在网上下了拜读了,贴在这里。并附上我写的程序。原书中的解法只对正整数,且有一点小问题。
我改正了错误,并把它推广到了支持负数的问题。
  1. if __name__ == '__main__':
  2.     a = [1,2,3,44]
  3.     b = [6,7,8,-9]
  4.     total = a + b

  5.     minAB = min(a+b)
  6.     modcut = max([0,-minAB+1]) # Deal with negative numbers by add a minmum negive number

  7.     halfSumAll = (sum(total)+(modcut)*len(total))/2
  8.     modifyTotal = [ modcut + i for i in total] # Motify numbers to all positive
  9.     n = len(total)/2

  10.     isOK=[]
  11.     for i in range(halfSumAll+1):
  12.         isOK.append([None for i in range(n+1)])
  13.     isOK[0][0]=set()

  14.     from pprint import pprint
  15.     for k in range(1,len(total)+1):
  16.         value = modifyTotal[k-1]
  17.         truevalue = total[k-1]
  18.         for i in range(min(n,k),0,-1): # Should from Max to minum to avoid calulate a k for twice in one run
  19.             for v in range(value,halfSumAll+1): # to cut value to select larger v to calulate
  20.                 if isOK[v-value][i-1] is not None:
  21.                     isOK[v][i] = set(isOK[v-value][i-1])
  22.                     isOK[v][i].add(k-1) # set index of select item
  23.    
  24.     for v in range(halfSumAll,0,-1):
  25.         if isOK[v][n] is not None:
  26.             print "Minumum abs(a-b):",(halfSumAll-v)*2
  27.             a = [total[k] for k in isOK[v][n]]
  28.             b = [total[k] for k in range(len(total)) if k not in isOK[v][n]]
  29.             print "a:",a
  30.             print "b:",b
  31.             break


复制代码

屏幕快照 2012-09-17 上午12.04.51.png (89.3 KB, 下载次数: 38)

屏幕快照 2012-09-17 上午12.04.51.png

屏幕快照 2012-09-17 上午12.06.09.png (203.07 KB, 下载次数: 42)

屏幕快照 2012-09-17 上午12.06.09.png

屏幕快照 2012-09-17 上午12.06.32.png (186.98 KB, 下载次数: 38)

屏幕快照 2012-09-17 上午12.06.32.png

屏幕快照 2012-09-17 上午12.06.49.png (51.58 KB, 下载次数: 36)

屏幕快照 2012-09-17 上午12.06.49.png

论坛徽章:
4
水瓶座
日期:2013-09-06 12:27:30摩羯座
日期:2013-09-28 14:07:46处女座
日期:2013-10-24 14:25:01酉鸡
日期:2014-04-07 11:54:15
7 [报告]
发表于 2012-09-17 14:41 |只看该作者
恩, 的确是这个, 楼主很有耐心啊.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP