能源消耗最大化
Maximize consumption Energy
提供了三种食物,即肉、蛋糕和披萨
和 N 个不同的商店出售它,我只能从中挑选一种食物
每家商店。此外,我只能购买 A、B 和 C 编号的商品,其中 'A' 表示来自 'A' 家不同商店的肉类(参见示例)。我的任务是
消耗食物,这样我才能拥有最大的能量。
例如,
10 <= number of stores <br>
5 3 2 <= out of 10 stores I can pick meat from 5 stores only. Similarly,
I can pick cake from 3 out of 10 stores...
56 44 41 1 <= Energy level of meat, cake and pizza - (56, 44, 41) for first store.<br>
56 84 45 2
40 98 49 3
91 59 73 4
69 94 42 5
81 64 80 6
55 76 26 7
63 24 22 8
81 60 44 9
52 95 11 10
所以为了最大化我的能量,我可以消耗...
肉店数量:
[1, 4, 7, 8, 9] => [56, 91, 55, 63, 81]
商店编号的蛋糕:
[3, 5, 10] => [98, 94, 95]
披萨店数量:
[2, 6] => [45, 80]
这使我最终获得了 758 的最大能量水平。
由于我是动态规划的新手,我试图通过生成独特的组合来解决它,
10C5 * (10-5)C 3 * (10-5-3)C2 = 2520
这是我的代码,
nStores = 10
a, b, c = 5, 3, 2
matrix = [
[56,44,41],
[56,84,45],
[40,98,49],
[91,59,73],
[69,94,42],
[81,64,80],
[55,76,26],
[63,24,22],
[81,60,44],
[52,95,11]
]
count = a + b + c
data = []
allOverCount = [i for i in range(count)]
def genCombination(offset, depth, passedData, reductionLevel = 3):
if (depth == 0):
first = set(data)
if reductionLevel == 3:
return genCombination(0,b,[i for i in allOverCount if i not in first], reductionLevel=2)
elif reductionLevel == 2:
return genCombination(0,c,[i for i in allOverCount if i not in first], reductionLevel=1)
elif reductionLevel == 1:
xAns = 0
for i in range(len(data)):
if i < a:
xAns += matrix[data[i]][0]
elif i < a + b:
xAns += matrix[data[i]][1]
else:
xAns += matrix[data[i]][2]
return xAns
oneData = 0
for i in range(offset, len(passedData) - depth + 1 ):
data.append(passedData[i])
oneData = max(oneData, genCombination(i+1, depth-1, passedData, reductionLevel))
del data[-1]
return oneData
passedData = [i for i in range(count)]
finalOutput = genCombination(0,a,passedData)
print(finalOutput)
我知道这不是正确的做法。我该如何优化它?
看来修改背包就可以解决。
让我们定义我们的 dp table 为 4 维数组 dp[N+1][A+1][B+1][C+1]
now some cell dp[n][a][b][c]表示我们已经考虑了n家店铺,从中我们挑选了一家卖肉的店铺,
b 店买蛋糕,c 店买披萨,它储存了我们可以拥有的最大能量。
转换也很容易,从某个状态 dp[n][a][b][c] 我们可以移动到:
- dp[n+1][a][b][c] 如果我们跳过 n+1 店
- dp[n+1][a+1][b][c] 如果我们买
n+1 店的肉
- dp[n+1][a][b+1][c]如果我们从n+1店买蛋糕
- dp[n+1][a][b][c+1] 如果我们从商店 n+1 购买披萨
剩下的就是填充 dp table。示例代码:
N = 10
A,B,C = 5,3,2
energy = [
[56, 44, 41],
[56, 84, 45],
[40, 98, 49],
[91, 59, 73],
[69, 94, 42],
[81, 64, 80],
[55, 76, 26],
[63, 24, 22],
[81, 60, 44],
[52, 95, 11]
]
dp = {}
for n in range(N+1):
for a in range(A+1):
for b in range(B+1):
for c in range(C+1):
dp[n,a,b,c]=0
answer = 0;
for n in range(N+1):
for a in range(A+1):
for b in range(B+1):
for c in range(C+1):
#Case 1, skip n-th shop
if (n+1,a,b,c) in dp: dp[n+1,a,b,c] = max(dp[n+1,a,b,c], dp[n,a,b,c])
#Case 2, buy meat from n-th shop
if (n+1,a+1,b,c) in dp: dp[n+1,a+1,b,c] = max(dp[n+1,a+1,b,c], dp[n,a,b,c] + energy[n][0])
#Case 3, buy cake from n-th shop
if (n+1,a,b+1,c) in dp: dp[n+1,a,b+1,c] = max(dp[n+1,a,b+1,c], dp[n,a,b,c] + energy[n][1])
#Case 4, buy pizza from n-th shop
if (n+1,a,b,c+1) in dp: dp[n+1,a,b,c+1] = max(dp[n+1,a,b,c+1], dp[n,a,b,c] + energy[n][2])
answer = max(answer,dp[n,a,b,c])
print(answer)
这是一个通过纸浆(https://pypi.org/project/PuLP)使用线性规划的解决方案,它给了我最优解
Maximum energy level: 758.0
Mapping of stores per foodtype: {1: [9, 2, 4], 0: [3, 8, 0, 6, 7], 2: [1, 5]}
我认为性能应该比手动编码的详尽求解器更好。
from collections import defaultdict
import pulp
# data
nStores = 10
a, b, c = max_stores = 5, 3, 2
matrix = [
[56, 44, 41],
[56, 84, 45],
[40, 98, 49],
[91, 59, 73],
[69, 94, 42],
[81, 64, 80],
[55, 76, 26],
[63, 24, 22],
[81, 60, 44],
[52, 95, 11]
]
# create an LP problem
lp = pulp.LpProblem("maximize energy", sense=pulp.LpMaximize)
# create the list of indices for the variables
# the variables are binary variables for each combination of store and food_type
# the variable alpha[(store, food_typeà] = 1 if the food_type is taken from the store
index = {(store, food_type) for store in range(nStores) for food_type in range(3)}
alpha = pulp.LpVariable.dicts("alpha", index, lowBound=0, cat="Binary")
# add the constrain on max stores
for food_type, n_store_food_type in enumerate(max_stores):
lp += sum(alpha[(store, food_type)] for store in range(nStores)) <= n_store_food_type
# only one food type can be taken per store
for store in range(nStores):
lp += sum(alpha[(store, food_type)] for food_type in range(3)) <= 1
# add the objective to maximise
lp += sum(alpha[(store, food_type)] * matrix[store][food_type] for store, food_type in index)
# solve the problem
lp.solve()
# collect the results
stores_for_foodtype = defaultdict(list)
for (store, food_type) in index:
# check if the variable is active
if alpha[(store, food_type)].varValue:
stores_for_foodtype[food_type].append(store)
print(f"Maximum energy level: {lp.objective.value()}")
print(f"Mapping of stores per foodtype: {dict(stores_for_foodtype)}")
提供了三种食物,即肉、蛋糕和披萨 和 N 个不同的商店出售它,我只能从中挑选一种食物 每家商店。此外,我只能购买 A、B 和 C 编号的商品,其中 'A' 表示来自 'A' 家不同商店的肉类(参见示例)。我的任务是 消耗食物,这样我才能拥有最大的能量。 例如,
10 <= number of stores <br>
5 3 2 <= out of 10 stores I can pick meat from 5 stores only. Similarly,
I can pick cake from 3 out of 10 stores...
56 44 41 1 <= Energy level of meat, cake and pizza - (56, 44, 41) for first store.<br>
56 84 45 2
40 98 49 3
91 59 73 4
69 94 42 5
81 64 80 6
55 76 26 7
63 24 22 8
81 60 44 9
52 95 11 10
所以为了最大化我的能量,我可以消耗...
肉店数量:
[1, 4, 7, 8, 9] => [56, 91, 55, 63, 81]
商店编号的蛋糕:
[3, 5, 10] => [98, 94, 95]
披萨店数量:
[2, 6] => [45, 80]
这使我最终获得了 758 的最大能量水平。
由于我是动态规划的新手,我试图通过生成独特的组合来解决它,
10C5 * (10-5)C 3 * (10-5-3)C2 = 2520
这是我的代码,
nStores = 10
a, b, c = 5, 3, 2
matrix = [
[56,44,41],
[56,84,45],
[40,98,49],
[91,59,73],
[69,94,42],
[81,64,80],
[55,76,26],
[63,24,22],
[81,60,44],
[52,95,11]
]
count = a + b + c
data = []
allOverCount = [i for i in range(count)]
def genCombination(offset, depth, passedData, reductionLevel = 3):
if (depth == 0):
first = set(data)
if reductionLevel == 3:
return genCombination(0,b,[i for i in allOverCount if i not in first], reductionLevel=2)
elif reductionLevel == 2:
return genCombination(0,c,[i for i in allOverCount if i not in first], reductionLevel=1)
elif reductionLevel == 1:
xAns = 0
for i in range(len(data)):
if i < a:
xAns += matrix[data[i]][0]
elif i < a + b:
xAns += matrix[data[i]][1]
else:
xAns += matrix[data[i]][2]
return xAns
oneData = 0
for i in range(offset, len(passedData) - depth + 1 ):
data.append(passedData[i])
oneData = max(oneData, genCombination(i+1, depth-1, passedData, reductionLevel))
del data[-1]
return oneData
passedData = [i for i in range(count)]
finalOutput = genCombination(0,a,passedData)
print(finalOutput)
我知道这不是正确的做法。我该如何优化它?
看来修改背包就可以解决。
让我们定义我们的 dp table 为 4 维数组 dp[N+1][A+1][B+1][C+1]
now some cell dp[n][a][b][c]表示我们已经考虑了n家店铺,从中我们挑选了一家卖肉的店铺, b 店买蛋糕,c 店买披萨,它储存了我们可以拥有的最大能量。
转换也很容易,从某个状态 dp[n][a][b][c] 我们可以移动到:
- dp[n+1][a][b][c] 如果我们跳过 n+1 店
- dp[n+1][a+1][b][c] 如果我们买 n+1 店的肉
- dp[n+1][a][b+1][c]如果我们从n+1店买蛋糕
- dp[n+1][a][b][c+1] 如果我们从商店 n+1 购买披萨
剩下的就是填充 dp table。示例代码:
N = 10
A,B,C = 5,3,2
energy = [
[56, 44, 41],
[56, 84, 45],
[40, 98, 49],
[91, 59, 73],
[69, 94, 42],
[81, 64, 80],
[55, 76, 26],
[63, 24, 22],
[81, 60, 44],
[52, 95, 11]
]
dp = {}
for n in range(N+1):
for a in range(A+1):
for b in range(B+1):
for c in range(C+1):
dp[n,a,b,c]=0
answer = 0;
for n in range(N+1):
for a in range(A+1):
for b in range(B+1):
for c in range(C+1):
#Case 1, skip n-th shop
if (n+1,a,b,c) in dp: dp[n+1,a,b,c] = max(dp[n+1,a,b,c], dp[n,a,b,c])
#Case 2, buy meat from n-th shop
if (n+1,a+1,b,c) in dp: dp[n+1,a+1,b,c] = max(dp[n+1,a+1,b,c], dp[n,a,b,c] + energy[n][0])
#Case 3, buy cake from n-th shop
if (n+1,a,b+1,c) in dp: dp[n+1,a,b+1,c] = max(dp[n+1,a,b+1,c], dp[n,a,b,c] + energy[n][1])
#Case 4, buy pizza from n-th shop
if (n+1,a,b,c+1) in dp: dp[n+1,a,b,c+1] = max(dp[n+1,a,b,c+1], dp[n,a,b,c] + energy[n][2])
answer = max(answer,dp[n,a,b,c])
print(answer)
这是一个通过纸浆(https://pypi.org/project/PuLP)使用线性规划的解决方案,它给了我最优解
Maximum energy level: 758.0
Mapping of stores per foodtype: {1: [9, 2, 4], 0: [3, 8, 0, 6, 7], 2: [1, 5]}
我认为性能应该比手动编码的详尽求解器更好。
from collections import defaultdict
import pulp
# data
nStores = 10
a, b, c = max_stores = 5, 3, 2
matrix = [
[56, 44, 41],
[56, 84, 45],
[40, 98, 49],
[91, 59, 73],
[69, 94, 42],
[81, 64, 80],
[55, 76, 26],
[63, 24, 22],
[81, 60, 44],
[52, 95, 11]
]
# create an LP problem
lp = pulp.LpProblem("maximize energy", sense=pulp.LpMaximize)
# create the list of indices for the variables
# the variables are binary variables for each combination of store and food_type
# the variable alpha[(store, food_typeà] = 1 if the food_type is taken from the store
index = {(store, food_type) for store in range(nStores) for food_type in range(3)}
alpha = pulp.LpVariable.dicts("alpha", index, lowBound=0, cat="Binary")
# add the constrain on max stores
for food_type, n_store_food_type in enumerate(max_stores):
lp += sum(alpha[(store, food_type)] for store in range(nStores)) <= n_store_food_type
# only one food type can be taken per store
for store in range(nStores):
lp += sum(alpha[(store, food_type)] for food_type in range(3)) <= 1
# add the objective to maximise
lp += sum(alpha[(store, food_type)] * matrix[store][food_type] for store, food_type in index)
# solve the problem
lp.solve()
# collect the results
stores_for_foodtype = defaultdict(list)
for (store, food_type) in index:
# check if the variable is active
if alpha[(store, food_type)].varValue:
stores_for_foodtype[food_type].append(store)
print(f"Maximum energy level: {lp.objective.value()}")
print(f"Mapping of stores per foodtype: {dict(stores_for_foodtype)}")