代码
def transition(M,N,strnum):
numList=['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J',\
'K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
#把M进制的num转化为10进制
numlength=len(strnum)
Ten_num=0
for i in range(1,numlength+1):
Ten_num=Ten_num+numList.index(strnum[-i])*(M**(i-1))
#把10进制的num转化为N进制
N_num=''
while Ten_num!=0:
N_num=numList[Ten_num%N]+N_num
Ten_num=Ten_num//N
return N_num
M,N=map(int,input().split())
strnum=input()
print(transition(M,N,strnum))
代码中需要注意的地方
M,N=map(int,input().split())
用来输入一行中含有多个整数
strnum[-i]
由于输入的原数字是字符串形式,并且数字的最低位在字符串的末尾,因而可以使用负数的索引方式
numList
的索引正好对应字符的十进制数,因而采用index索引得到字符对应的十进制数
numList.index(strnum[-i])
由于输入的strnum是字符串形式,因而numList中的0-9不要写作整数类型
numList[Ten_num%N]
对字符串索引取值要用中括号
N_num=numList[Ten_num%N]+N_num
加法前后顺序不可以变化,保证除k取余法中对余数取得顺序
代码
num=int(input())
memory=[0 for i in range(num+1)]#记忆
def dp(n):#n是盘子总数
#结束条件
if n==0:
memory[0]=0
return 0
elif n==1:
memory[1]=1
return 1
elif n==2:
memory[2]=3
return 3
#其他情况
else:
if memory[n]!=0:
return memory[n]
else:
step=[]
for k in range(1,n):
step.append(2*dp(k)+2**(n-k)-1)
memory[n]=min(step)
return min(step)
print(dp(num))
详解
假设四根柱子命名分别为a b c d,需要把盘子从a柱移动到d柱:
函数dp(n)代表把n个盘子进行移动所需要的最少步骤
1、我们设将a柱最上边的k个圆盘(1<=k<n)借助b、d两个柱子移动到c上需要dp[ k ] 步
2、然后我们再把a柱上剩下的n-k个盘借助b柱移动到d柱上(不能借助c, c上的都小),那么这一步骤和三柱汉诺塔是一样的,是 2^(n-k)-1步
3、最后我们再把c上的k个圆盘借助a、b移动到d上,同样需要F[ k ]步
4、但是,要得到最小值,需要把k遍历一遍
代码中要注意的几点
- 输入的盘子总数是非负整数,因而要在代码中考虑 n=0的情况
- 为减少递归层数,可以采用函数值缓存的方法,本代码中使用了memory列表缓存
- k的取值范围如果k取0,则只用到了三根柱子,一定不会是最优解;如果k取n,则先把所有盘子从a移到c,再从c移到d,显然不是最优解。同时,如果k取n的话,在递归调用的过程中会出现自己调用自己的状况,陷入了死循环。(禁止套娃!!)