楼主海外留学生,昨晚参加了宇宙节的算法笔试,被折磨的死去活来。。。最后一题背包问题,当时有思路但是没想清楚怎么实现,后来时间不够了唉。今天把代码写出来了,希望有大佬可以看一下正确与否。
题目内容:
第一行输入三个数N, M, S。第二行输入一个包含N个数的数列 L[i], i=0,...,N-1.
要求:输出选取任意数量的数字使其总和达到S。运算过程中可以对数字进行阶乘,但是每个数字只能最多阶乘一次,而且阶乘运算的总数不能大于M。
输入例子:
3 1 1
1 1 1
输出例子:
6
输入例子:
3 2 6
1 2 3
输出例子:
5
这道题是背包问题的变形中的求方案总数问题,这是个二维问题(S,M)。其状态转移方程为:G[v, m] = G[v, m]+G[v-L[i]][m]+G[v-L[i]!][m-1]。初始状态为G[0][0] = 1。但是考试时没想明白如何去限制每个数只能做一次阶乘,目前的想法是使用一个状态数组status[v][m]记录达到总和v时有没有对L[i]做阶乘运算,如果已经做了阶乘,G[v,m]就不能从G[v-L[i]!][m-1]得到。最后本题的答案就是sum(G[S][:])。
以下是具体python代码:
def cal(num):
#计算阶乘
res = num
for i in range(num-1, 1, -1):
res *= i
return res
while True:
try:
N, M, S = list(map(int, input().split())
L = list(map(int, input().split())
G = [[0 for _ in range(M+1)] for _ in range(S+1)]
G[0][0] = 1
for i in range(N):
#记录阶乘使用情况的数组status
status = [[0 for _ in range(M+1)] for _ in range(S+1)]
for v in range(S, L[i]-1, -1):
G[v][0] = G[v][0] + G[v-L[i]][0]
for k in range(1, M+1):
G[v][k] = G[v][k] + G[v-L[i]][k]
temp = cal(L[i])
if v-temp>=0 and status[v-temp][k-1]==0:
G[v][k] = G[v][k] + G[v-temp][k-1]
#此处使用了阶乘,所以将status[v][k]设置为1
status[v][k] = 1
print (sum(G[S][:]))
except:
break