题目:
第一个想法,求出1~n的全排列,按字典序排列,然后从头依次对排列进行 *** 作,得出结果在和sum对比,找出第一个符合要求的序列。
结果这样做会超时,只有四十分
all_s = [] # 存储所有序列 def perm(h, r): # 求所有的序列 global all_s, lst if h >= r: all_s.append(lst.copy()) return for i in range(h, r): lst[i], lst[h] = lst[h], lst[i] perm(h+1, r) lst[i], lst[h] = lst[h], lst[i] n, m = map(int, input().split()) lst = [x for x in range(1, n+1)] perm(0, n) all_s.sort() # 按字典序对所有排列进行排序 # print(all_s) for i in all_s: l = len(i) temp = i.copy() while l: # 按题目要求求和 for j in range(0, l-1): i[j] = i[j] + i[j+1] l -= 1 if i[0] == m: # 如果符合要求就输出序列,并退出循环 for p in temp: print(p, end=" ") break
第二个想法,通过观察序列中每个数字被加的次数,可以发现每个数字被加的次数和n-1的所有组合数有关,就拿样例来说
3 1 2 4
4 3 6(1 ,2 ,2 ,1)
7 9(1 , 3 , 3 , 1)= (C30 , C31 , C32 , C33)
16
所以我们可以先求出n-1的所有组合数,然后对每个组合数枚举对应位置的数字
def COMB(x): # 动态规划求组合数,也可以用python自带的函数求,math.comb lst = [[1 for _ in range(x+1)] for _ in range(x+1)] for i in range(2, x+1): for j in range(1, i): lst[i][j] = lst[i-1][j] + lst[i-1][j-1] return lst[x] def solution(n, m, lst, vis, p, temp, re): if p == n: if temp == m: print(str(re).strip('[]').replace(',', '')) vis[0] = 1 # 标记,代表已经找到答案,第一个输出的找到的排列就是答案 return 0 if not vis[0]: # 当标记为1时,代表当前已经输出了最优答案,不需要在继续找了 for i in range(1, n+1): if vis[i] == 0: re[p] = i # 记录当前位置数字 vis[i] = 1 # 标记这个数字用过了 if temp+re[p]*lst[p] <= m: # 约束条件,当和大于m时,是无效的解,没有这个约束条件只有90分 solution(n, m, lst, vis, p+1, temp+re[p]*lst[p], re) vis[i] = 0 # 将数字恢复到没用过的状态,递归回来的时候让后面的位置可以用这个数字 n, m = map(int, input().split()) re = [0 for _ in range(n)] # 记录排列 lst = COMB(n-1) # 存储n-1的所有组合数 # print(lst) vis = [0 for _ in range(n+1)] # 标记数组,防止排列中数字重复 solution(n, m, lst, vis, 0, 0, re)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)