回溯算法——收费公路重建问题python实现

来源:互联网 发布:阮佳 黄光剑 网络战 编辑:程序博客网 时间:2024/05/01 08:02

收费公路重建问题

数据结构与算法分析(C语言描述)原书第二版,P304  回溯算法:

书中给出了详细分析,并给出了伪代码,根据书上的伪代码,写了个python实现的。


简单一点说这个问题就是根据给定的条件求N个未知数,N个未知数分别代表公路上的N个点(也可以当作坐标轴上的N个点),

这里用[x1, x2, x3,...,xN]表示,而给定的条件为任意两个点间距离的集合及{|xi - xj|, i,j=1,2,3,...,N 且 i!=j},根据统计学知识可知,这

个集合的元素有N*(N-1)/2个(从N个元素中任取两个的方法数)。


如果给定一个解[x1, x2, x3,...,xN],那么将每个元素加上同一个常量C那么又能得到一组满足条件的解,所以这里直接将x1=0,即只

求x1=0时的一组解;


x1=0之后,这里对于xN就应该等于集合{|xi - xj|, i,j=1,2,3,...,N 且 i!=j}中的最大值,还拿书上的例子:

集合D = {1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 7, 8, 10}   共15个元素,可得出共有6个点[x1, x2, x3, x4, x5, x6],

1. 确定了x1 = 0, x6 = 10,从D中删除10得到剩下的集合 {1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 7, 8},其中最大的

元素为8,那么这里将x5 = 8,或者将x2 = 2,这两种情况相互对称,要么都有解,要么都无解,这里设置x5 = 8; 并将8从D中删除


2. 确定了 x1 = 0, x5 = 8, x6 = 10, 剩下的集合D为{1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 6, 7},最大元素为7

到此要分两种情况了,x4 = 7 或者 x2 = x6 - 7=3:

首先假设x4 = 7 ,接下来验证假设对不对:

如果假设正确,那么x4与前面几步中确定的x1, x5和x6之间的距离,肯定都在剩下的集合D中,

将这些距离删除掉剩下集合{2, 2, 3, 3, 4, 5, 5, 5, 6}:

接着在分两种情况:x3 = 6 或 x2 = 4,同样是假定一种情况正确然后与前面确定的或者假定正确的x求

距离如果正确则从集合中删除,直到集合被删空(即找到解了)

如果前面假设不正确,说明x4 = 7不能导出解,所以需要回溯回去,考虑x2 = x6-7=3的情况;

 代码:

# -*- coding: cp936 -*-import sysclass turnpike_problem:    def __init__(self, n, D):        self.x = [0]*(n+1)#从x[1:]表示解         self.n = n        self.D = D[:]        self.D.sort()        def place(self, n, D, left, right):        found_flag = False                if len(D) == 0:            #print '^_^: ',self.x[1:]            return True        Dmax = max(D)        tmpD = D[:]        set_right = True        for i in range(1, left)+range(right+1, n+1):            if abs(self.x[i]-Dmax) not in tmpD:                set_right = False                break            tmpD.remove(abs(self.x[i]-Dmax))                if set_right == True:            self.x[right] = Dmax            for i in range(1, left)+range(right+1, n+1):                D.remove(abs(self.x[i]-Dmax))            found_flag = self.place(n, D, left, right-1)            if found_flag == False:                for i in range(1, left)+range(right+1, n+1):                    D.append(abs(self.x[i]-Dmax))                #D.sort()        if found_flag == False:            tmpD = D[:]            set_left = True            for i in range(1, left)+range(right+1, n+1):                if abs(self.x[n]-Dmax-self.x[i]) not in tmpD:                    set_left = False                    break                tmpD.remove(abs(self.x[n]-Dmax-self.x[i]))                            if set_left == True:                self.x[left] = self.x[n]-Dmax                for i in range(1, left)+range(right+1, n+1):                    D.remove(abs(self.x[n]-Dmax-self.x[i]))                found_flag = self.place(n, D, left+1, right)                                if found_flag == False:                    for i in range(1, left)+range(right+1, n+1):                        D.append(abs(self.x[n]-Dmax-self.x[i]))                    #D.sort()        return found_flag            def turnpike(self, n, D):        self.x[n] = max(D)        D.remove(self.x[n])        self.x[n-1] = max(D)        D.remove(self.x[n-1])        if self.x[n]-self.x[n-1] in D:            D.remove(self.x[n]-self.x[n-1])            return self.place(n, D, 2, n-2)        else:            return False    def show(self):        if self.turnpike(self.n, self.D):            print 'found:', self.x[1:]        else:            print 'not'def main():    sys.setrecursionlimit(1000)        #D = [1, 2, 2, 2, 3, 3, 3, 4, 5, 5, 5, 6, 7, 8, 10]    D = [1, 2, 2, 3, 4, 5]    t = turnpike_problem(4, D)    t.show()if __name__ == '__main__':    main()



0 0
原创粉丝点击