Chinaunix

标题: 【华为公司Python面试题】,要求10分钟写出代码。。。 [打印本页]

作者: 天魔封神霸    时间: 2009-06-26 14:13
标题: 【华为公司Python面试题】,要求10分钟写出代码。。。
有两个序列a,b,大小都为n,序列元素的值任意整形数,无序;
要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。



附带一下我们的组织:
游戏开发-2群:Python(78676826),主要讨论:
桌面:WxWidget、TK、GTK、QT
游戏:pyOGRE、pyGame、"python.h"
Web:Zope、Django
网络:Twisted
只要心中有梦就可以与我们为伍!Game Developer欢迎志同道合的朋友加入。

[ 本帖最后由 天魔封神霸 于 2009-6-26 14:41 编辑 ]
作者: bawbaw    时间: 2009-06-27 10:29
def look(a, max = 0):
    a.sort()
    while 1:
        if len(a) == 0:return None
        val = a.pop()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if val <= max:return val


def ab(a , b):
&nbsp;&nbsp;&nbsp;&nbsp;a.extend(b)
&nbsp;&nbsp;&nbsp;&nbsp;sum = reduce(lambda x,y:x+y, a)
&nbsp;&nbsp;&nbsp;&nbsp;arvg = sum / 2.0

&nbsp;&nbsp;&nbsp;&nbsp;rs1 = []
&nbsp;&nbsp;&nbsp;&nbsp;def qq(arvg, pick = None):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if pick is None:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pick = a.pop()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a.remove(pick)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rs1.append(pick)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arvg -= pick
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pick = look(a[:], max = arvg)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if pick is not None:qq(arvg, pick)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;qq(arvg)
&nbsp;&nbsp;&nbsp;&nbsp;print rs1, a
ab([1,2,5,3],[6,7,8,9,10])


[ 本帖最后由 bawbaw 于 2009-6-27 10:44 编辑 ]
作者: broader    时间: 2009-06-27 15:47
原帖由 天魔封神霸 于 2009-6-26 14:13 发表
有两个序列a,b,大小都为n,序列元素的值任意整形数,无序;
要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。

http://wiki.services.openoffice.org/w/images/7/7e/Python_po ...

题面描述中:“整形数”是什么数?正整数、整数还是什么其它的数?
如果是正整数,想到的一个算法描述如下:
1 将a、b序列中的元素合并到一个长度为2n的list中并排序,假定此list名称为c;
3 创建两个空list分别命名为x,y
2 构建一个函数假设名称为add2list,该函数的作用是将两个正整数添加到x,y中,保证这x,y的元素之和的差值的绝对值最小;
3 对c中的元素依次两两分组递归调用前面的函数add2list
4 最后得到的x,y即为所求之结果

[ 本帖最后由 broader 于 2009-6-28 11:32 编辑 ]
作者: 天魔封神霸    时间: 2009-06-28 13:56
整形数,我没说清楚,就是指 整数
作者: ruiqingzheng    时间: 2009-06-28 17:20
标题: 回复 #1 天魔封神霸 的帖子
比如 [1..100]  这样的一个list
切成两个LIST 并让两个list的和之间的差的绝对值最小
不就是[1..25] [100..76] 组成一个list
另外的[26..75] 组成一个list
这两个LIST的元素和的差为0 当然是绝对值最小的了

所以  只用把两个LIST 排序成一个LIST后切片    就可以得到这样的两个LIST , 对吧?
作者: iamkey9    时间: 2009-07-01 13:48
最小怎么定义,这个是问题,0不是最小。
作者: guijia8427    时间: 2009-07-01 14:30
10分钟? 有难度哦
作者: weizhe86    时间: 2009-07-01 14:35
ruiqingzheng

发表于 2009-6-28 17:20
            比如 [1..100]  这样的一个list
切成两个LIST 并让两个list的和之间的差的绝对值最小
不就是[1..25] [100..76] 组成一个list
另外的[26..75] 组成一个list
这两个LIST的元素和的差为0 当然是绝对值最小的了

所以  只用把两个LIST 排序成一个LIST后切片    就可以得到这样的两个LIST , 对吧?
肯定不对喽[1,2,3,4,5,6,700,800],如何
作者: gdh    时间: 2009-07-02 01:25
提示: 作者被禁止或删除 内容自动屏蔽
作者: weizhe86    时间: 2009-07-02 07:58
标题: 回复 #9 gdh 的帖子
也不对
S=[10001,10000,100,90,50,1]
如何
是a=[10001,90,50]
   b=[10000,100,1]
差为40
还是a=[10001,100,1]
      b=[10000,90,50]
差为38
您的方案显然是前者。
作者: nkchenz    时间: 2009-07-02 12:29
贴一个试试

#l = range(1, 11)
l = [10001,10000,100,90,50,1]
#l = [1,2,3,4,5,6,700,800]
l.sort(reverse = True)

def sl(l):
    s = 0
    for i in l:
        s += i
    return s

avg = sl(l) / 2 # 求和的平均
print avg

r = []
for i in l: # 从大到小遍历
    s = sl(r + [i])
    if s < avg:
        r.append(i)
    elif s == avg:
        r.append(i)
        break
    else:
        # 当新加入的i大于avg时,需要特殊处理。
        if not r:
            r.append(i)
            continue
        t1 = s - i
        t2 = sl(r[:-1]) + i
        if abs(t1 - avg) > abs(t2 -avg): # 看新的i是否比上一个i为优
            r = r[:-1] + [i]

print r


[ 本帖最后由 nkchenz 于 2009-7-2 12:34 编辑 ]
作者: eookoo    时间: 2009-07-02 14:05
标题: 回复 #11 nkchenz 的帖子
如果:
l = [12312, 12311, 232, 210, 30, 29, 3, 2, 1, 1]

# ur answer:
12551 = [12312, 232, 3, 2, 1, 1]  
12580 = [12311, 210, 30, 29]      
差 29


12559 = [12312, 210, 30, 3, 2, 1, 1]
12572 = [12311, 232, 29]
差13
作者: gdh    时间: 2009-07-02 16:22
提示: 作者被禁止或删除 内容自动屏蔽
作者: nkchenz    时间: 2009-07-02 17:28
标题: 回复 #12 eookoo 的帖子
理解上也有偏差,题目要求最后的两个列表还是等长
作者: weizhe86    时间: 2009-07-03 14:12
标题: 回复 #13 gdh 的帖子
Source List:    [1, 2, 3, 4, 5, 6, 700, 800]
Result List:    [1, 4, 5, 800] [2, 3, 6, 700]
Distance:       99

应该是

Source List:    [1, 2, 3, 4, 5, 6, 700, 800]
Result List:    [1,2,3,800] [4,5,6,700]
Distance:       91

另外
Source List:    [1, 1, 2, 3, 29, 30, 210, 232, 12311, 12312]
Result List:    [1, 3, 29, 232, 12311] [1, 2, 30, 210, 12312]
Distance:       21
也不对

应该是
a=[1,1,29,232,12311]
b=[2,3,30,210,12312]
差为17

[ 本帖最后由 weizhe86 于 2009-7-3 15:10 编辑 ]
作者: gdh    时间: 2009-07-03 16:19
提示: 作者被禁止或删除 内容自动屏蔽
作者: weizhe86    时间: 2009-07-03 22:36
标题: 回复 #11 nkchenz 的帖子
sl可以直接使用sum函数嘛
另外你少考虑一些东西
作者: weizhe86    时间: 2009-07-04 16:41
标题: 大家可以用这个程序检测自己的结果是不是正确
#coding=utf-8
souce=[12312, 12311, 232, 210, 30, 29, 3, 2, 1, 1]
souce.sort(reverse=True)
l=len(souce)
avg=sum(souce)/2.0
def changeone(n,liu):
    li=liu
    lis=[[v for v in li]]
    for i in range(l):
        if not i in liu:
            li[n]=i
            lis.append([v for v in li])
    lin=[]
    if n<l/2-1:
        for lii in lis:
            lin+=(changeone(n+1,lii))
    return lin+lis
li=changeone(1,range(l/2))
mincha=sum([souce[x] for x in li[0]])
for i in li:
    s=sum([souce[x] for x in i])
    if abs(s-avg)<abs(avg-mincha):
        mincha=s
        print mincha*2-sum(souce),[souce[x] for x in i]

将所有分组方法的结果都计算出来,输出差值最小的那种分法。效率最慢(华为不会使用这种方法的),能保证准确性,随意推荐给大家做检查用。
作者: needspeedboy    时间: 2009-07-05 04:05
把两个序列合并,然后排序,然后索引奇分一个列,索引偶数再分一个列就行了.
作者: weizhe86    时间: 2009-07-06 17:16
标题: 回复 #19 needspeedboy 的帖子
你觉得华为会出这么幼稚的题目吗
作者: wudi626    时间: 2009-07-07 00:07
# coding=gb2312
# 有两个序列a,b,大小都为n,序列元素的值任意整形数,无序;
# 要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。

def FindTargetItem(diff,lst):
    for item in lst:
        if diff >= item:
            return lst.index(item)
        else:
            return -1

def Process(lstA,lstB):
    sumA = sum(lstA)
    sumB = sum(lstB)
   
    lstA.sort()
    lstB.sort()
   
    if sumA == sumB:
        return
    elif sumA > sumB:
        diff = sumA - sumB
        while diff >= 0:
            targetIndex = FindTargetItem(diff,lstA)
            if targetIndex == -1:
                return
            else:
                lstB.append(lstA.pop(targetIndex))
            sumA = sum(lstA)
            sumB = sum(lstB)
            diff = sumA - sumB
    else:
        diff = sumB - sumA
        while diff >= 0:
            targetIndex = FindTargetItem(diff,lstB)
            if targetIndex == -1:
                return
            else:
                lstA.append(lstB.pop(targetIndex))
            sumA = sum(lstA)
            sumB = sum(lstB)
            diff = sumB - sumA
    return
作者: wudi626    时间: 2009-07-07 00:24
原帖由 wudi626 于 2009-7-7 00:07 发表
# coding=gb2312
# 有两个序列a,b,大小都为n,序列元素的值任意整形数,无序;
# 要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。

def FindTargetItem(diff,lst):
    for ...



仔细看了下,这个算法不符合要求!
作者: edgar    时间: 2009-07-07 11:35
'''
Created on 2009-7-7

@author: Edgar
'''
def getDif(aList,bList):
    asum=0;
    bsum=0;
   
    for eachItemIndex in range(len(aList)):
        asum+=aList[eachItemIndex];
        bsum+=bList[eachItemIndex];
    return bsum-asum
def getMaxValue(aList,bList):
    aList.sort()
    aMax=aList[-1]
    bList.sort()
    bMax=bList[-1]
    if aMax<bMax:
        return bMax
    else:return aMax
   
def getTheProperPairs(aList,bList):
    theDif=getDif(aList, bList)
    theMinmum={"aList":0,"bList":0,"diff":getMaxValue(aList, bList)}
    for i in aList:
        for k in bList:
            theTempDif=2*(k-i)
            if theTempDif==theDif:
                theMinmum["diff"]=theTempDif
                theMinmum["aList"]=i
                theMinmum["bList"]=k
                return theMinmum
               
            if theMinmum["diff"]>abs(theTempDif-theDif):
                theMinmum["diff"]=abs(theTempDif-theDif)
                theMinmum["aList"]=i
                theMinmum["bList"]=k
   
    return theMinmum
是说只准交换一个吗?还是允许交换多个?交换位置有要求吗?
我这个程序是只准许一个,交换位置没有要求
作者: sysengcn    时间: 2009-07-07 13:19
为什么童鞋们总喜欢把简单问题复杂化呢?

其实只要想着让 sum(X) 和 sum(Y) 都往 ( sum(A) + sum(B) ) / 2 上靠不就完了吗。(这里假设 A, B 为源 list, X, Y 为所求的 list。)

因为只有当 sum(X) 和 sum(Y) 都最靠近那个中间点的时候,他们的差才会最小,对吧?


A = [1, 2, 700, 6]
B = [4, 3, 5, 800]
X = []
Y = []

pivot = ( sum(A) + sum(B) ) / 2

C = A + B
C.sort()

def next_one(sum) :
    if sum > pivot :
        return C.pop(0)
    else :
        return C.pop(-1)

while len(C) :
    if abs(sum(X) - pivot) > abs(sum(Y) - pivot) :
        # X is further away to pivot than Y, let X pick first
        X.append( next_one( sum(X) ) )
        Y.append( next_one( sum(Y) ) )
    else :
        # otherwise let Y pick first
        Y.append( next_one( sum(Y) ) )
        X.append( next_one( sum(X) ) )

print X
print Y
print abs(sum(X) - sum(Y))


[ 本帖最后由 sysengcn 于 2009-7-6 21:21 编辑 ]
作者: edgar    时间: 2009-07-08 09:17
sysengcn ,你这是不限次数的调换啊……
作者: weizhe86    时间: 2009-07-08 23:26
标题: 提醒大家一个问题
一,题目要求的是差值最小的方案,所以交换一对数据是不能实现的。
二,最后交换一对数据无法使差值减小,但是存在同时交换两对(还有更多对)数据可以减小差值的可能。
作者: weizhe86    时间: 2009-07-08 23:30
标题: 回复 #24 sysengcn 的帖子
你这个问题,前边已经说过不对了,为什么还要发。
作者: newman0708    时间: 2009-07-21 15:46


  1. def sumlist(list1):
  2.     retsum=0
  3.     for i in list1:
  4.         retsum=retsum+i
  5.     return retsum


  6. def getminutegap(a1):
  7.     minutegap=[]
  8.     for i in xrange(len(a1)-1):
  9.         val1=a1[i]
  10.         val2=a1[i+1]
  11.         gap=abs(val1-val2)
  12.         minutegap.append(gap)
  13.     return minutegap

  14. def getmaxvalueindex(list1):
  15.     maxv=max(list1)
  16.     return list1.index(maxv)
  17.    
  18. def dividelist(a1,b1):
  19.     a1.extend(b1)
  20.     aaa=[]
  21.     bbb=[]
  22.     a1.sort()
  23.     a1.reverse()
  24.     print a1

  25.     while(len(a1)>1):
  26.         maxgapindex=getmaxvalueindex(getminutegap(a1))
  27.         if sumlist(aaa)<=sumlist(bbb):
  28.             aaa.append(a1[maxgapindex])
  29.             bbb.append(a1[maxgapindex+1])
  30.         else:
  31.             aaa.append(a1[maxgapindex+1])
  32.             bbb.append(a1[maxgapindex])            
  33.         a1.remove(a1[maxgapindex])
  34.         a1.remove(a1[maxgapindex])

  35.     if (len(a1)>0) and (sumlist(aaa)<sumlist(bbb)):
  36.         aaa.append(a1[0])

  37.     aaasum=sumlist(aaa)
  38.     bbbsum=sumlist(bbb)
  39.     print aaa,aaasum,bbb,bbbsum,(sumlist(aaa)-sumlist(bbb))

  40.         

  41.    
  42. #dividelist([1,2,5,3],[6,7,8,9,10])
  43. #dividelist([300, 200],[ 150, 53, 12, 3])




  44. dividelist([10001,10000],[100,90,50,1])
  45. # 1001 1000 10 8 5 1
  46. # 1001 8  5  =1014
  47. # 1000 10 1  =1011

  48. # 1001 10 1  =1012
  49. # 1000 8  5  =1013

  50. dividelist([101,100],[10, 8, 5, 1])
  51. # 101 100 10 8 5 1
  52. # 101 8  5  =113
  53. # 100 10 1  =111

  54. # 101 10 1  =112
  55. # 100 8  5  =113


复制代码

作者: luxyi    时间: 2009-08-04 14:35
这题目就是考算法,跟 Python 没什么关系。
作者: doctorwho    时间: 2009-08-05 00:54
网上Google到的,觉得有道理,大家讨论一下,有更好的算法吗?
   
   求解思路:

    当前数组a和数组b的和之差为
    A = sum(a) - sum(b)

    a的第i个元素和b的第j个元素交换后,a和b的和之差为
    A' = sum(a) - a + b[j] - (sum(b) - b[j] + a)
           = sum(a) - sum(b) - 2 (a - b[j])
           = A - 2 (a - b[j])
    设x = a - b[j]

    |A| - |A'| = |A| - |A-2x|

    假设A > 0,

    当x 在 (0,A)之间时,做这样的交换才能使得交换后的a和b的和之差变小,x越接近A/2效果越好,

    如果找不到在(0,A)之间的x,则当前的a和b就是答案。

    所以算法大概如下:

    在a和b中寻找使得x在(0,A)之间并且最接近A/2的i和j,交换相应的i和j元素,重新计算A后,重复前面的步骤直至找不到(0,A)之间的x为止。


[ 本帖最后由 doctorwho 于 2009-8-5 00:56 编辑 ]
作者: Lonki    时间: 2009-08-05 14:11
动态规划
Python会有这样的面试, 还是10分钟, 还是广告...
作者: starfuck    时间: 2009-08-24 00:57
本帖最后由 starfuck 于 2019-11-26 23:48 编辑













作者: ypyf3000    时间: 2009-08-26 11:33
十分钟怎么可能做出来,蒙人
作者: szwe    时间: 2009-08-28 17:27
穷举好了,又没要求算法的最优,反正也就是o(N^3)的复杂度
作者: shopokey    时间: 2009-08-29 00:41
都有几个月没看python的代码了,看到这个题目还真的搞不出...
作者: toakee    时间: 2009-08-31 08:56
标题: 回复 #1 天魔封神霸 的帖子
#!/usr/bin/env python
# python 2.4+

a = [20,5,3]
b = [2,1,1]

def sum(lst):
    return reduce(lambda x,y: x+y,lst)

def do(d):
    global a,b
    x = -1

    for i in xrange(a):
        for j in xrange(b):
            c = a[ i] - b[j]
            if c > 0 and c <= d/2:
                if x == -1 or  c > x:
                    x = c
                    ai = i
                    bj = j

    if x == -1:
        return False
    else:
        a[ai],b[bj] = b[bj],a[ai]
        return True

def main():
    global a,b
    while True:
        if sum(a) < sum(b):
            a,b = b,a
        a.sort(reverse=True)
        b.sort(reverse=True)
        Diff = sum(a) - sum(b)

        if do(Diff):
            continue
        else:
            print a
            print b
            break

if __name__ == '__main__':
    main()


[root@web ~]# python test.py
[20, 1, 1]
[2, 5, 3]

虽然代码比较臃肿,但基本功能能实现。

[ 本帖最后由 toakee 于 2009-9-8 10:42 编辑 ]
作者: starfuck    时间: 2009-09-02 00:39
本帖最后由 starfuck 于 2019-11-26 23:48 编辑













作者: redskywy    时间: 2009-09-07 09:56
负数不比0小的吗?
作者: 爱斯基摩寂寞    时间: 2009-09-10 15:42
我觉得楼主很无聊 大家每说一个他就说也不对 比如。。。。你干脆给出答案得了 卖什么关子 你说成ibm的面试题得了
作者: tangboyun    时间: 2010-01-29 20:55
解法思路在此:

http://blog.csdn.net/tangboyun/archive/2010/01/29/5270785.aspx
                                                                                      
为什么我说我的解法是这个问题的最优解?

依赖于三个特性:

一、就是交换a1和b1中的元素后,得到的新的a'和b'序列,它们依旧是从大到小排列的。无需再sort!!

二、得到的a1和b1序列,其下标,和之后用以操作swap函数的下标及求最合适石块(最合适的数值差),存在一个简单的转换关系。

三、 $smallRock[0]一定是原先2n个元素中,任意两元素差值的最小值!!!这个对用来测试最后还要不要交换,是至关重要的,没有这个概念的解法,不可能得到正确答案!!!!
作者: shhgs    时间: 2010-01-29 23:40
很难。10分钟肯定不够。我想算法得20分钟。真正出代码得一个小时。

顺便说一句,针对这道题,所有“投机取巧”的算法,我都表示怀疑。因为你们没有办法用数学证明你们的算法是可靠的。

[ 本帖最后由 shhgs 于 2010-1-29 23:52 编辑 ]
作者: lxguidu    时间: 2010-01-29 23:48
看来我的能力不行啊,各位都是高手,领教了!
作者: shhgs    时间: 2010-01-30 00:06
其实这道题还真不是考你们算法的。这是考你们的数据结构的。照着题目的意思,用swap元素的方式调整。要说算法,其实就是设计一个停止的条件。就是判断当前情况下,没有可调整的元素了。


  1.     a1          a2          a3      a4 ...
  2. b1  (1,1),m1   (1,2),m2     ...
  3. b2  ...
  4. b3  ...
  5. .
  6. .
  7. .
复制代码

很明显,这是一个dict,键就是序列a和b的下标(tuple),值就是他们的差。

这里的停止条件是,n = sum(a) - sum(b) 和这个dict里面的所有值的比较(假设某个值为m)。有两个条件
1. m 和 n 符号相同(同正或同负)
2. |m - n| < n
然后,选 |m - n| 最小的那个m,找出其对应的a和b的下标,swap两个元素。

[ 本帖最后由 shhgs 于 2010-1-30 06:22 编辑 ]
作者: nankai559    时间: 2010-04-28 22:45
以上所有非指数级算法都不对,因为此问题至少是NP-Complete.

理由:
将两个数组合并后从小到大排序,然后a'取前一半小值,b'取后一半大值。
这里假设一种简化情况,就是我们只需交换a',b'中相同位置的元素就可获得最优解(实际情况要更加复杂)。
然后我们将数组C设为b'-a',是一组正整数; 设正整数T为(sum(b')-sum(a'))/2。现在问题变为:

1. 一组正整数集合C,目标正整数T, 求C中的一个子集使得此子集的和在不超过T的情况下越大越好,

2. 一组正整数集合C,目标正整数T, 求C中的一个子集使得此子集的和在不小于T的情况下越小越好。

问题1被称为子集和问题(subset sum problem),可以看做是背包问题的一个特例。此问题是NP-Complete的。

两个关于subset sum problem的链接:
http://www.cs.dartmouth.edu/~ac/ ... /nanda-scribe-3.pdf
http://en.wikipedia.org/wiki/Subset_sum_problem

因为本问题的一个简化情况都是NP-Complete的,所以这个问题本身至少是NP-Complete的。
作者: Kabie    时间: 2010-05-20 08:09
  1. def gotans(a,b):
  2.         c=sorted(a+b,reverse=(sum(a+b)>0))
  3.         S=sum(c)
  4.         s=abs(S)
  5.         S=S/2
  6.         for i in itertools.combinations(c,len(a)):
  7.                 tmp = abs(sum(i)-S)
  8.                 if tmp<s:
  9.                         s=tmp
  10.                         print(s,sum(i),i)
  11.                         if tmp==0 or tmp==0.5:
  12.                                 break
复制代码
...10分钟也只好先穷举了……效率非常低。。。。
作者: litanhe    时间: 2010-05-21 19:24
1. 合并两个数组
2. 数组排序,
3. 如果最小数是负数,则所有元素先加上其绝对值
4. 分配序列:
   序列1和序列2默认sum为零
    分配序列到序列1,直到求和大于序列2,然后其余数分配到序列2,直到序列2求和和大于序列1
  终止:某个序列数目达到n,未分配序列分配到另一序列组
这样得到的两个序列求和差值是否最小?
作者: aoma    时间: 2010-05-28 23:15
我的想法
数组从大到小排序得到数组A(A1,A2,A3,...A2n)
建两个新数组B,C,先从A取最大的两个元素,分别给B,C,到底sum(B)和sum(C)谁大不重要,如果B大则C取第三个,如果C大则B取第三个,第四个元素取最后的元素A2, B和C得到两个元素后,开始计算sum,谁小取第A4个元素,依次类推
作者: pikyshen    时间: 2010-05-30 21:03
提示: 作者被禁止或删除 内容自动屏蔽
作者: fisherjams    时间: 2010-06-05 01:41
给你个思路八

两个序列合并求和并求平均值avg
min=avg-avg*n/2
max=avg+avg*n/2

最后a序列为>=min且<=max的数,b序列为其他

用a,b交换实现上述结果
作者: fisherjams    时间: 2010-06-05 01:50
在进一步

先对ab分别排序,a从大向小,b从小向大

a和b 在min和max之间有交集,对交集互换,过avg点后交换方向相反
作者: FisherGray    时间: 2011-03-10 17:44
  1. def fun(list_a,list_b,index):     
  2.     if list_a[index+1] >= list_b[index]:
  3.         _copy=list_b[index]
  4.         list_b[index]=list_a[index+1]
  5.         list_a[index+1]=list_b[index+1]
  6.         list_b[index+1]=_copy
  7.     elif list_a[index+1] < list_b[index] and list_a[index+1] > list_b[index+1]:
  8.         _copy=list_b[index+1]
  9.         list_b[index+1] = list_a[index+1]
  10.         list_a[index+1] = _copy
  11.     return list_a,list_b

  12. def exchange_elments_of_two_lists(list_a,list_b):   
  13.     list_a.sort(reverse=True)
  14.     list_b.sort(reverse=True)
  15.     for index in xrange(0,len(list_a)-1):
  16.         if list_a[index] > list_b[index]:           
  17.             [list_a,list_b]=fun(list_a,list_b,index)        
  18.         elif list_a[index] < list_b[index]:           
  19.             [list_b,list_a]=fun(list_b,list_a,index)         
  20.     return list_a,list_b
复制代码

作者: FisherGray    时间: 2011-03-10 17:48
python made it easy, Right?
作者: a515200    时间: 2011-03-10 18:31
和上次我发的最大子段和实现算法一样,仍用递归实现,我将把效率抛诸脑后,
作者: weihengsi    时间: 2011-03-11 12:50
华为就是不一样啊

思路是有啊,可是10分钟有点少啊,说不定是打错字什么的,都要使时间超过10分钟啊,这人生啊
作者: ixuh    时间: 2011-03-12 14:09
  1. la = [3, 34, 435, 45, 3, 34, 678, 3245]
  2. lb = [23, 3, 12, 3245, 234, 457, 345, 435]

  3. def split(lst):
  4.     halfsize = len(lst) / 2
  5.     return lst[:halfsize], lst[halfsize:]

  6. la, lb = split(sorted(la + lb))
  7. print sum(la) - sum(lb)
复制代码

作者: a515200    时间: 2011-03-12 22:37
不要一大堆人围进来,整天喊着思路,要么你就贴代码,要么你们就飘过

好比大学生学数据结构,概念理论说的头头是道,编起程来一个代码都敲不了
作者: a515200    时间: 2011-03-12 22:37
看清楚题目,大佬..
作者: ixuh    时间: 2011-03-14 13:03
回复 57# a515200


    有什么不对呢? 难道你能找到比-8917更小的差...
作者: a515200    时间: 2011-03-14 13:41
这个题目实际上应该叫做    两序列元素的总和之差的绝对值应为最小,我想华为的人是故意这样做的,有点故弄玄虚


题目要求是:
要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。
应该列出两个交换后的序列
作者: 专操五毛    时间: 2011-03-18 14:26
本帖最后由 专操五毛 于 2011-03-18 14:30 编辑

.....................................................................................................
作者: d_bsky    时间: 2012-05-06 19:36
按照我的思想,就是先合并两个序列a跟b,得到c,然后排序c,再分割c,左右端同时取值,一次放d,一次放e,最后得到de两个list,这个应该就是差值最小的了吧
作者: qinscx    时间: 2012-05-07 11:57
按照我的思想,就是先合并两个序列a跟b,得到c,然后排序c,再分割c,左右端同时取值,一次放d,一次放e,最后得到de两个list,这个应该就是差值最小的了吧

楼上的思路和我的一样,另一种等同的做法是:合并之后排序,按奇偶分割成两个序列即为所求。
理由:合并排序后,针对第一个元素,试想序列里元素,谁和他的差距最小?当然是第二个。这样,一二元素分离。再来考虑第三个元素,同样的道理,三四元素分开。这样,最后的结果是:元素最小差距1 + 元素最小差距2 + 。。。 = 两个序列的最小差距。
作者: dknlnl    时间: 2012-05-07 21:34
本帖最后由 dknlnl 于 2012-05-07 22:11 编辑

每个序列之和越靠近总和的1/2,那么是两个序列这差越小.
考虑反贪心算法.
将两个序列合并,排序,记为sortList.
设x,y为结果序列.
x依次从sortList中取数,从最小的开始取.直到sum(x)>=sum(sortList)/2.

假设x从sortList取出一个数k反,sum(x)从小于sum(sortList)/2变为大于或等于sum(sortList)/2,根据以下条件判断k是否放入x:
如果将k加入x后,x的和与y(y就是sortList减于x啦)之差小于将k不放入x,那么k放入x.
以上是不要求结果序列等长的.

作者: CMAX    时间: 2012-06-01 17:54
本帖最后由 CMAX 于 2012-06-01 17:54 编辑

python的,纯实现,没考虑其他的
  1. #! /usr/bin/env python

  2. import input
  3. a = input.a
  4. b = input.b

  5. l = len(a)

  6. ar = list()
  7. br = list()

  8. sl = sorted(a + b, reverse = True)

  9. diff = 0

  10. sign = True

  11. for i in xrange(0, l):
  12.     for j in range(2*l-1, i+1, -1):
  13.         d1 = sl[i] - sl[j-1]
  14.         d2 = sl[i] - sl[j]
  15.         if diff - d1 >= 0 and diff - d2 < 0:
  16.             r1, r2 = i, j
  17.             break
  18.     else:
  19.         r1, r2 = i, i+1

  20.     if sign:
  21.         ar.append(sl[r1])
  22.         br.append(sl[r2])
  23.     else:
  24.         ar.append(sl[r2])
  25.         br.append(sl[r1])
  26.     sign = not sign

  27. print ar, sum(ar)
  28. print br, sum(br)
复制代码

作者: bskay    时间: 2012-08-29 11:35
本帖最后由 bskay 于 2012-08-29 15:42 编辑

伪动态规划的,

#动态规划问题
#从M个数里面找出N个,让他们的和尽量接近 P
class NumList:
        def __init__(self):
                self.reset()
                pass
        def reset(self):
                self.vA = []
                self.vB = []
                self.nSumA = reduce(lambda x, y: x+y, self.vA, 0)
                self.nSumB = reduce(lambda x, y: x+y, self.vB, 0)
                pass
        #开始规划
        def addonce(self,nA,nB):
                #
                if self.nSumA > self.nSumB:
                        self.vA.append(nA)
                        self.nSumA += nA
                        self.vB.append(nB)
                        self.nSumB += nB
                        pass
                else:
                        self.vA.append(nB)
                        self.nSumA += nB
                        self.vB.append(nA)
                        self.nSumB += nA
                        pass
                #try
                while self.ajduest():pass
                return
        def ajduest(self):
                if self.nSumA>self.nSumB:
                        nA,nB = self.findd(self.vA,self.vB,(self.nSumA-self.nSumB)/2)
                        if nA is None or nB is None:
                                return False
                        pass
                elif self.nSumA<self.nSumB:
                        nB,nA = self.findd(self.vB,self.vA,(self.nSumB-self.nSumA)/2)
                        if nA is None or nB is None:
                                return False
                        pass
                else:
                        return False
                self.nSumA += self.vB[nB] - self.vA[nA]
                self.nSumB += self.vA[nA] - self.vB[nB]
                print 'r1(vA,vB) =',self.vA,self.vB
                self.vA[nA],self.vB[nB] = self.vB[nB],self.vA[nA]
                self.vA.sort()
                self.vB.sort()
                print 'r2(vA,vB) =',self.vA,self.vB
                return True
        #
        '''
        输入:
                I1. A中所有元素的和大于B中所有元素的和
                I2. A,B中的元素从小到大排列
                I3. 最大期望的调整值
        输出:
                O1. 在A,B中分别找出一个位置(a,b)
                O2. 交换调整A,B中对应的元素后,依然满足I1
                O3. 没有找到满足条件一个位置,返回None
        '''
        def findd(self,vA,vB,nDlt):
                print 'findd',vA,vB,nDlt
                nA,nB = None,None
                nXXX = nDlt
                for a in xrange(len(vA)-1,-1,-1):
                        for b in xrange(len(vB)):
                                if vB >= vA[a]:
                                        break
                                nDiff = vA[a]-vB #调整的差值
                                if nDiff > nDlt:
                                        continue
                                if nDlt-nDiff >= nXXX:
                                        continue
                                if nDiff == nDlt:
                                        print 'haha findd at ... ',a,b
                                        return a,b
                                #print '(vB,vA[a]) =',(vB,vA[a]),'(a,b)',(a,b), 'r =',nDiff
                                nXXX = nDlt-nDiff
                                nA,nB = a,b
                                continue
                        continue
                print 'findd at ... ',nA,nB
                return nA,nB
        def main(self,vA,vB):
                self.reset()
                vX = vA+vB
                vX.sort()
                while len(vX):
                        self.addonce(vX[0],vX[1])
                        del vX[:2]
                        continue
                print 'vA =>',self.vA
                print 'vB =>',self.vB
                return
        pass


self = NumList()
self.main([1,1,1,1],[2,2,2,2])
assert(self.vA == [1,1,2,2] and self.vA==self.vB)

self.main([1,1,1,1],[1,1,1,1])
assert(self.vA == [1,1,1,1] == self.vB)

self.main([1,1,2,3,5,10,], [20,30,30,50,50,100,])


作者: Hadron74    时间: 2012-08-29 16:38
本帖最后由 Hadron74 于 2012-08-29 20:00 编辑

看了前人的解法,怎么把问题搞得那么复杂。这个题目是十分钟的题目,肯定没有那么多代码的。

我的思路是用穷举法,把所有的a+b的total的序列的排列穷举,得到所有可能的划分,对其差值计算最小值。

下面是程序,
  1. def minus(total):
  2.         n = len(total)/2
  3.         a = total[:n]
  4.         b = total[n:]
  5.         return abs(sum(a)-sum(b)),a,b

  6. def func(total,k):
  7.         mi,am,bm = minus(total)
  8.         global minusN,an,bn
  9.         if mi < minusN:
  10.                 minusN = mi
  11.                 an,bn = am,bm

  12.         for i in range(k,len(total)):
  13.                 total[k],total[i] = total[i],total[k]
  14.                 func(total,k+1)
  15.                 total[k],total[i] = total[i],total[k]

  16. a=[1,2,3,4]
  17. b=[6,7,8,9]
  18. an,bn = a[:],b[:]
  19. total = a+b
  20. minusN,am,bm=minus(total)
  21. func(total,0)
  22. print "a:",an
  23. print "b:",bn
  24. print "minus:",minusN

复制代码
这里的算法用到了穷举一个序列的全排列的算法,见
http://www.cnblogs.com/height/archive/2012/08/14/2638802.html

这个算法的复杂性太过要O((2n)!),我的写法中也有冗余的部分,有时间来改正。
这里抛砖引玉,也许有更短小的写法。肯定有更快的算法,我正在寻找中。


作者: Hadron74    时间: 2012-09-12 19:03
本帖最后由 Hadron74 于 2012-09-12 19:13 编辑

回复 66# Hadron74


    现在我有了一个更好的方法,用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]
复制代码

作者: new_ray    时间: 2012-09-16 20:59
我觉得就是一个排序问题吧。
比如:序列a1,a2,a3,...an
         序列b1,b2,b3,...bn
         假设存在一个序列c,c的元素为a1,a2,a3...an,b1,b2,b3...bn.对序列c排序后得到新的顺序,c1,c2,c3..c2n.则得到序列a结果为c1,c3,c5...c2n-1,序列b为c2,c4,c6...c2n.
而排序可以只比较就可以了。
作者: Hadron74    时间: 2012-09-17 00:21
回复 68# new_ray

这个问题没有那么简单,详细请看我们最新的帖子。《编程之美》给出了正整数的动态规划算法。我写了代码。

http://bbs.chinaunix.net/forum.p ... age%3D1#pid22286448

   
作者: new_ray    时间: 2012-09-22 07:09
呵呵,写完后就发现自己写错了,后来又有了一种想法。仍然是先排序,得到c1,c2,c3..c2n。然后将cn+1,cn+2...c2n数据与前面的进行交换。每次选取的值都是要是差值最小(>0)的数对。
1.若使得cn+1,cn+2...c2n与c1,c2...cn的差值变大时就结束。
2.若cn+1,cn+2...c2n与c1,c2...cn的差值为负数时,如果负数的绝对值变小时仍然交换。
3.再将c1,c2...cn与与后面的进行交换。每次选取的值都是要是也差值最小(>0)的数对。
4.处理与1,2步骤类似。

呵呵,这样应该是可以了。
作者: songjun54cm    时间: 2012-09-22 11:33
回复 3# broader


    +1
作者: http80    时间: 2012-09-22 22:09
感觉好难的样子
作者: Hadron74    时间: 2012-09-23 18:04
回复 3# broader

这个算法有问题,每两个绝对值最小,不一定是总和最小。正确解法见我从《编程之美》学的算法。见帖子:
    http://bbs.chinaunix.net/thread-3770708-1-1.html
作者: Hadron74    时间: 2012-09-23 18:10
本帖最后由 Hadron74 于 2012-09-23 18:40 编辑

回复 70# new_ray

如果不遍历所有交换是不可能到最优的。看我上一个帖子。

但是处理所有的交换,原则上解决了,问题是你如何遍历所有的交换,其算法复杂程度如何?请给出程序。

这个一个典型的最优化问题,必须遍历所有解空间。
如果不考虑问题的整数性,其算法复杂度最好的可能是按我写的0-1背包程序,请参考我的程序。
当然如果有更快的算法,我也希望向你学习。

如果是整数,动态规划算法的复杂性好得多。


   
作者: Hadron74    时间: 2012-09-23 18:45
本帖最后由 Hadron74 于 2012-09-23 18:56 编辑

回复 71# songjun54cm

那是错误的方法。
   
作者: webdna    时间: 2012-09-27 10:30
就华为两个字,引无数人看这个帖
作者: kangxuechao    时间: 2012-10-09 23:48
本人新建了一个500 的python QQ 群, 群号:  248814126,  欢迎加入!!!
作者: dylan_yiu    时间: 2012-10-10 10:04
本帖最后由 dylan_yiu 于 2015-04-27 18:03 编辑

xxxxxxxxxxxxx
作者: nheddd113    时间: 2012-10-10 20:51
def changelist(aList,bList):
        cList=[]
        cList=aList + bList
        del aList,bList
        aList=[]
        bList=[]
        cList.sort()
        count=0
        for i in cList:
                count+=1
                if count % 2 ==0:
                        bList.append(i)
                        count+=1
                        if len(bList)-len(aList)>=1:
                                count+=1
                else:
                        aList.append(i)
        return(aList,bList)

这样不知道算不算是
作者: Hadron74    时间: 2012-10-11 08:45
回复 79# nheddd113

你这个程序的算法有问题。不能保证最优化条件。详细请看我以前的帖子。
   
作者: nheddd113    时间: 2012-10-11 10:17
回复 80# Hadron74

我看了一下. 好象是一样.呵呵.看来不过关了

   
作者: xinxinhao    时间: 2013-03-01 11:59
本帖最后由 xinxinhao 于 2013-03-01 12:01 编辑

回复 1# 天魔封神霸


这个问题很简单吧 ,技巧即可,求相差最小,先求最大,再反过来不就是最小咯 ?

最小的意思是 (所有最小的和) 减去 (所有最大的和)  === 相差结果 最小了

(最小 当然可是是负数啊)


a=[1,45435,54,67,545]
b=[54,656,76576,2,54]

c=a+b
c=c.sort()

a=c[0:len(a)]
b=c[len(a):]

此时 和相差最小

====完了,就这么简单=====
作者: 523066680    时间: 2013-03-01 21:55
opengl用户路过
作者: pitonas    时间: 2013-03-07 09:57
webdna 发表于 2012-09-27 03:30
就华为两个字,引无数人看这个帖
不算广告吧
作者: 酷了个cool    时间: 2013-03-22 15:35
a[1,5,3,9,2]
b[0,7,8,4,6]
c=[1,5,3,9,2,0,7,8,4,6]
c=[0123456789]
a   b
0   9
8   1
7   2
3   6
4   5
这样?
作者: ArtsCrafts    时间: 2013-03-25 10:53
假设a=[5,4,8,6,10] b=[15,13,10,18,20]
(1)将两个序列合并为一个序列,并且排序.得到序列[4,5,6,8,10,10,13,15,18,20]。
(2)在将该序列切分为((4,5),(6,,(10,10),(13,15),(18,20))。
(3)按照大小交替分配,假设A第一次去小的数也就是4,那么下一次它将取打的数也就是8.这样依次交替着取。
(4)最后取得a,b序列a=[4,8,10,15,18], b=[5,6,10,13,20],最后两序列之差为1。
不知这种想法对不对。

作者: ArtsCrafts    时间: 2013-03-25 19:42
代码贴出来:
  1. def cross(a, b):
  2.         temp = a + b
  3.         temp.sort()
  4.         i = j = k = 0
  5.         for n in range(0, len(temp), 2):
  6.                 if k%2 == 0:
  7.                         a[i] = temp[n]
  8.                         b[j] = temp[n+1]
  9.                 else:
  10.                         a[i] = temp[n+1]
  11.                         b[j] = temp[n]
  12.                 i = i + 1
  13.                 j = j + 1
  14.                 k = k + 1
  15. def sum(a):
  16.         s = 0
  17.         for i in a:
  18.                 s = s + a
  19.         return s
  20. a = [5, 4, 8, 6, 10]
  21. b = [15, 13, 10, 18, 20]
  22. cross(a, b)
  23. print sum(a) - sum(b)
复制代码

作者: 没把儿菜刀    时间: 2013-11-07 20:35
回复 82# xinxinhao


    擦,我理解错了,简单问题复杂化。
我是把a和b两个列表合二为一成c,sort,reverse,然后把a和b清零,从c里从大到小往a和b两遍分配,每次用一个求和函数看那边儿小就往那边儿加,保证两串和的差别最小。不过原题说的是“交换两串元素”,也就是说两串的长度都是不变的

那我倒叙了之后按照大小一边儿一个就行了吧?
作者: 没把儿菜刀    时间: 2013-11-07 20:38
回复 82# xinxinhao


    你这个结果不能保证是两个串互相“交换”元素能得到的结果吧……
作者: 没把儿菜刀    时间: 2013-11-07 20:49
回复 40# tangboyun


    我怎么觉得这个答案是错的,37楼的那个才是对的呢?因为原题的前提是“交换两个串里的元素”,而您这个算法其实把原来两个列表里头的元素彻底打乱了,得出来的不一定是能够通过“交换元素”得到的结果
作者: 初识orcl    时间: 2013-11-08 13:53
顶起来,小伙伴们加油
作者: xiaot7151    时间: 2013-11-24 20:43
数学上的解法是 把两个序列 合并到一起 ,然后任意取N个,这N个的和减去剩下N个和的绝对值存入一个数组。共有 C2N(N) 种取法,所以结果数组长度是 2N!/N!, 然后取这个数组里面最小的正整数··

Python代码如何实现就不太清楚了··
作者: xiaot7151    时间: 2013-11-24 20:46
继续补充 -每一次取都要把相应的取出N个数再次存入一个数组(这样可以在再后计算出最小差值后能返回到对应的N个数)。感觉这程序性能跑起来会比较有问题,如果N比较大的话。。回复 92# xiaot7151


   
作者: freeterman    时间: 2013-11-26 10:56
回复 1# 天魔封神霸


#!/usr/bin/env python
a = [3, 8, 11, 8, 234]
b = [1, 2, 7, -21, 567]
x = y = 0
minSum = abs(sum(a)) - abs(sum(b))
while x < len(a):
    while y < len(b):
        a[x], b[y] = b[y], a[x]
        temp = abs(abs(sum(a)) - abs(sum(b)))
        if minSum < temp:
            a[x], b[y] = b[y], a[x]
        else:
            minSum = temp
        y = y + 1
    x = x + 1
    y = 0
print minSum
作者: freeterman    时间: 2013-11-26 11:05
使[序列a元素的和]与[序列b元素的和]之间的差最小
回复 82# xinxinhao


   
作者: zengbo1019    时间: 2013-11-28 14:22
这样可以么

def exchange(list1, list2):
   
    for i in range(len(list1)):
        for j in range(len(list2)):
            
            dvalue1=abs(sum(list1)-sum(list2))
            
            temp1 = list1[i]
            temp2 = list2[j]
            
            sum1 = sum(list1) + temp2 - temp1
            sum2 = sum(list2) + temp1 - temp2
            
            dvalue2=abs(sum1-sum2)
            if dvalue2 < dvalue1:
                list1[i] = temp2
                list2[j] = temp1

    print list1,sum(list1)
    print list2,sum(list2)
   
if __name__=="__main__":

    list1 = [10001,10000,100]
    list2 = [90,50,1]
    exchange(list1, list2)

[1, 10001, 100] 10102
[10000, 90, 50] 10140
作者: hejekele    时间: 2015-02-04 11:29
本帖最后由 hejekele 于 2015-02-04 11:30 编辑
  1. def change(alist=[], blist=[]):
  2.     asum = sum(alist)
  3.     bsum = sum(blist)

  4.     if asum == bsum:
  5.         return alist, blist

  6.     avg = (asum + bsum)/2

  7.     alist.sort()
  8.     alist.reverse()
  9.     blist.sort()


  10.     alen = len(alist)
  11.     blen = len(blist)

  12.     delta = abs(avg - asum)

  13.     for i in xrange(alen):
  14.         for j in xrange(blen):
  15.             tmp = alist[i] - blist[j]
  16.             if tmp <= 0:
  17.                 break
  18.             elif tmp <= delta:
  19.                 alist[i], blist[j] =  blist[j], alist[i]
  20.                 return change(alist, blist)
  21.     return alist, blist


  22. def call_change(alist=[], blist=[]):
  23.     asum = sum(alist)
  24.     bsum = sum(blist)
  25.     if asum < bsum:
  26.         a,b = change(blist, alist)
  27.         return b, a
  28.     else:
  29.         return change(alist, blist)
复制代码

作者: inpool    时间: 2015-02-05 09:52
思路:
合并两个列表,排序,然后按顺序从后往前每次取两个元素a, b,则a >= b
将取出来的数按a-b的值b进行分组
将分组按a-b的值排序然后合并,得到一个长为n的列表listab = [(a1,b1), (a2,b2), (a3,b3), ..., (an,bn)]
可证(listab[0] - listab[1]) >= (listab[i-1][0] - listab[i-1][1])  (0<= i < n)
定义两个空序列lista, listb
然后按从后往前的顺序取出listab的值并根据sum(lista)-sum(listb)的值,将ai,bi压入数组lista或listb
压入第一个时,abs(sum(lista) - sum(listb))最大,然后逐渐减小。
这个算法简单,实现也简单,思考5分钟,代码3-5分钟。
  1. def min_sub_of_sum(lista, listb):
  2.     listab = lista + listb
  3.     listab.sort()
  4.     tmp = {}
  5.     while listab:
  6.         a = listab.pop()
  7.         b = listab.pop()
  8.         tmp.setdefault(a-b, []).append((a, b))
  9.     subs = tmp.keys()
  10.     subs.sort()
  11.     for sub in subs:
  12.         listab.extend(tmp[sub])
  13.     lista, listb = [], []
  14.     # sub == sum(lista) - sum(listb)
  15.     sub = 0
  16.     while listab:
  17.         if sub < 0:
  18.             a, b = listab.pop()
  19.         else:
  20.             b, a = listab.pop()

  21.         lista.append(a)
  22.         listb.append(b)
  23.         sub += (a - b)
  24.     return lista, listb


  25. if __name__ == '__main__':
  26.     lista = range(100)
  27.     listb = [i^11 for i in lista]
  28.     a, b = min_sub_of_sum(lista, listb)
  29.     print a
  30.     print b
  31.     print sum(a) - sum(b)
复制代码

作者: turtle264    时间: 2015-04-07 23:39
1. 两个列表合成一个大的,并且求所有数的和除以2,假定是M
2.经过第一步,这个问题变成了0-1背包问题,背包容量是M
作者: vity    时间: 2015-04-13 11:08
bskay 发表于 2012-08-29 11:35
伪动态规划的,

#动态规划问题



问题就是在数组a[n]中查找m个数据数据之和为指定数据取整(sum / 2),如果能找到,就结束,如果不能就找  [sum / 2] - 1,逐渐找下去。
至于优化的事情可以慢慢考虑。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2