最短加法链问题

问题描述

最优求幂问题:给定一个正整数n和一个实数x,如何用最少的乘法次数计算出xn 。 例如,可以用 6 次乘法逐步计算 x23 如下: x,x2,x3,x5,x10,x20,x23 。可以证明 计算 x23 最少需要 6 次乘法。计算 x23 的幂序列中各幂次 1,2,3,5,10,20,23 组成了一 个关于整数 23 的加法链。在一般情况下,计算 xn 的幂序列中各幂次组成正整数 n 的一个加法链:
1=a0<a1<a2<…<ar=n

ai=aj+ak,k≤j<i,i=1,2,…,r

上述最优求幂问题相应于正整数 n 的最短加法链问题,即求 n 的一个加法链使其长度 r 达到最小。正整数n的最短加法链长度记为l(n)。

对于给定的正整数 n ,编程计算相应于正整数 n 的最短加法链。

数据输入:
第 1 行有 1 个正整数 n。

我这里写的是迭代回溯,便于理解。
如果看完还是不理解的话,可以在每步操作后面加上输出语句。

#输出加法链
def Print(x,num):
    for i in range(1,num+1):
        print(x[i],end=" ")
    print()
#回退到上一个元素
def Back(x,Sum,Add,num):
    #x[num]=0
    Sum-=x[Add[num]]#减去上一步添加的元素
    Add[num+1]=num+1#恢复Add[num]
    num=num-1
    return x,Sum,Add,num
def ADD(n):
    x=[0 for i in range(n+1)]#当前加法链
    #加法链的第一个元素是1,第二个一定是2
    x[1]=1
    x[2]=2
    Sum=2#当前计算的和
    num=2#当前加法链的长度为1
    bestx=[0 for i in range(n+1)]#最优加法链
    Add=[i for i in range(n+1)]#Add[i]记录当前链第i个元素的加数的下标
    Add[2]=1
    bestnum=n#最优加法链的长度最大为n
    i=2#下一个要加的加数的下标
    while True:
        #找加法链上的第num+1个元素
        while Sum+x[i]<=n and num+1<=bestnum:
            Sum+=x[i]
            num+=1
            Add[num]=i
            i=Add[num+1]-1#为下一次尝试做准备
            x[num]=Sum
        if Sum==n:
            bestx=list(x)
            bestnum=num
            #Print(bestx,bestnum)
            #当找到一种解之后,只倒退一步或者两步时是不会再出现链长更短的解的
            x,Sum,Add,num=Back(x,Sum,Add,num)
            x,Sum,Add,num=Back(x,Sum,Add,num)
            x,Sum,Add,num=Back(x,Sum,Add,num)
            i=Add[num+1]-1
            Add[num+1]=i
        else:
            #第num+1个元素加上之后链长大于最优解时回退到上一个元素
            if num+1>bestnum:
                x,Sum,Add,num=Back(x,Sum,Add,num)
                x,Sum,Add,num=Back(x,Sum,Add,num)
            i=Add[num+1]-1
            Add[num+1]=i#更新加数的下标
        while i<1:#第num+1个元素的所有可加项都尝试过
            x,Sum,Add,num=Back(x,Sum,Add,num)#回退到上一个元素
            i=Add[num+1]-1
            Add[num+1]=i
        if num<2:#所有元素的所有可加项都尝试过
            return bestx,bestnum

#从文件中读出数据
file_readpath = 'input.txt'
with open(file_readpath) as file:
    txt = file.read()
n=eval(txt)

#输出结果用于验证
bestx,bestnum=ADD(23)
print("最短链长:",bestnum-1)
print("链中的元素:")
Print(bestx,bestnum)

#将结果存入文件output.txt
file_writepath = 'output.txt'
file=open(file_writepath,"w")
file.write(str(bestnum-1)+'\n')
for i in range(1,bestnum+1):
    file.write(str(bestx[i])+' ')
file.close()

运行结果

在这里插入图片描述

发布了28 篇原创文章 · 获赞 4 · 访问量 2475

猜你喜欢

转载自blog.csdn.net/weixin_45050042/article/details/103248032
今日推荐