我最近开始学习动态编程,我发现了以下问题:
想象一下,你有一系列N种葡萄酒在一个架子上彼此相邻放置。为简单起见,让我们从左到右对葡萄酒进行编号,因为它们分别以1到N的整数站在货架上。第i款葡萄酒的价格是pi(不同葡萄酒的价格可能不同)。
因为葡萄酒每年变得更好,假设今天是第1年,第i年葡萄酒的价格将是y * pi,即y倍于当年的价值。
你想卖掉你所有的葡萄酒,但是你想要从今年开始每年出售一种葡萄酒。还有一个限制因素 - 每年你只允许卖掉货架上最左边或最右边的葡萄酒,你不能重新订购货架上的葡萄酒(即它们必须保持与开始时相同的顺序) )。
如果您以最佳顺序销售葡萄酒,您想知道,您可以获得的最大利润是多少。
答案是自上而下的方法,我想创建一个自下而上的方法。以下是我定义问题的方法:
F(l,r)是从指定的左右索引中选择葡萄酒而产生的利润函数
INPUT:p是葡萄酒价格的一系列
F(l,r)= max(年* p [l] + F(l + 1,r)*(年+ 1), 年* p [r] + F(l,r-1)*(年+ 1))
约束:l + r< = len(p)
我创建了以下Python代码来解决问题
def wine(Price):
length = len(Price)
DP = [[0] * (length+1) for _ in range(length+1)]
for y in range(1,length+1): #Or can be range(length, 0, -1):
for l in range(0, length):
for r in range(length-1, -1, -1):
if l+r <= length:
DP[l][r] = max(y * Price[l] + DP[l+1][r] * (y+1), \
y * Price[r] + DP[l][r-1] * (y+1))
return DP
我已将Price数组设置为[2,3,5,1,4]。消息来源表明Max Profit为50.但是,我无法用我编写的代码识别该值。有人可以用我的逻辑帮助识别问题吗?
答案 0 :(得分:1)
您需要考虑的几点:
int bottomUp(vector<int>price, int year, int start, int end)
{
int dp[100][100] = {0};
dp[start][start] = year*price[start];
for(int j=start+1; j<=end; j++)
{
for(int i=j; i>=0; i--)
{
int m = year-(j-i);
int x = m*bottle[j] + dp[i][j-1];
int y = m*bottle[i] + dp[i+1][j];
dp[i][j] = max(x,y);
}
}
return dp[start][end];
}
此处的代码返回可能的最大值 但是,我还粘贴了DP阵列外观的屏幕截图
答案 1 :(得分:0)
要解决这个问题,我们需要以不同的顺序迭代数组。从左上角开始,我们按年获得以下值:
l
所以每年我们需要迭代一条对角线而不是r
和def wine(price):
length = len(price)
DP = [[0] * (length+1) for _ in range(length+1)] # +1 for year0 in the corner
for y in range(1,length+1): # y1, y2... yN
for x in range(y+1): # intermediate values 0 to y
l = x # which is used to calculate the real l, r
# so, for the first year we get tuples (0, 1) and (1, 0)
r = y - l # we just go along the diagonal
# magic with l/r > 0 is used to prevent unwanted negative indexes
# so, False and price[-1] = False and max(False, 4) = 4
DP[l][r] = max(l > 0 and DP[l-1][r] + y * price[l-1], \
r > 0 and DP[l][r-1] + y * price[-r])
return DP
上的双循环。所以,代码是:
>>> pprint(wine([2,3,5,1,4]))
[[0, 4, 6, 21, 33, 43],
[2, 10, 13, 33, 48, 0],
[8, 20, 25, 50, 0, 0],
[23, 40, 50, 0, 0, 0],
[27, 47, 0, 0, 0, 0],
[47, 0, 0, 0, 0, 0]]
试运行:
{{1}}
答案 2 :(得分:0)
这里 i 和 j 分别表示给定 wines 数组的开始和结束索引。
重复:
max(wines[i] * year + maxProfit( i + 1, j, year + 1),
wines[j] * year + maxProfit( i, j - 1, year + 1));
自上而下 DP
int maxProfit_td(int *wines, int i, int j, int year, int dp[][100])
{
// Base Case
if (i > j)
return 0;
//Look Up
if (dp[i][j] != 0)
return dp[i][j];
// Recursive Case
int op1 = wines[i] * year + maxProfit_td(wines, i + 1, j, year + 1, dp);
int op2 = wines[j] * year + maxProfit_td(wines, i, j - 1, year + 1, dp);
return dp[i][j] = max(op1, op2);
}
自下而上 DP
int maxProfit_bu(int *wines, int n)
{
int dp[100][100] = {0};
// Wines array size
int year = n;
// Fill the diagonal elements i.e leaf nodes in case of recursion tree
for (int i = 0; i < n; i++)
dp[i][i] = year * wines[i];
year--;
// For remaining upper triangle
for (int len = 2; len <= n; len++)
{
int start = 0, end = n - len;
while (start <= end)
{
int cur = start + end - 1;
dp[start][cur] = max(wines[start] * year + dp[start + 1][cur],
wines[cur] * year + dp[start][cur - 1]);
start++;
}
year--;
}
return dp[0][n - 1];
}
函数调用
int dp[100][100] = {0};
cout << maxProfit_td(wines, 0, n - 1, 1, dp) << endl;
cout << maxProfit_bu(wines, n) << endl;