这是一项任务,我花了两天的时间来提出一个解决方案,但仍然有很多困惑,但是在这里我需要清楚几点。以下是问题:
Yuckdonald's正考虑在QVH开设一系列餐厅。 n个可能的位置沿着一条直线,这些位置距QVH起点的距离以英里为单位,并以递增的顺序 m1,m2,....,mn 。约束如下:
1.在每个地点,Yuckdonald可以开设一家餐厅,预计在 i 开设餐厅的利润为 pi
2.任何两家餐馆应至少相隔 k 英里,其中 k 是正整数
我的解决方案:
public class RestaurantProblem {
int[] Profit;
int[] P;
int[] L;
int k;
public RestaurantProblem(int[] L , int[] P, int k) {
this.L = L;
this.P = P;
this.k = k;
Profit = new int[L.length];
}
public int compute(int i){
if(i==0)
return 0;
Profit[i]= P[i]+(L[i]-L[i-1]< k ? 0:compute(i-1));//if condition satisfies then adding previous otherwise zero
if (Profit[i]<compute(i-1)){
Profit[i] = compute(i-1);
}
return Profit[i];
}
public static void main(String args[]){
int[] m = {0,5,10,15,19,25,28,29};
int[] p = {0,10,4,61,21,13,19,15};
int k = 5;
RestaurantProblem rp = new RestaurantProblem(m, p ,k);
rp.compute(m.length-1);
for(int n : rp.Profit)
System.out.println(n);
}
}
这个解决方案给了我88但是如果我排除(餐厅25岁,利润13)并包括(餐厅28,利润19)我最多可以有94个..
如果我错了,请指出我,或者如果真的如此,我怎么能实现这一点。
答案 0 :(得分:2)
我能够发现2个错误:
,您只是将结果存储在数据结构中,如果程序以您编写的方式工作并且您只进行了1次递归调用,那么这对性能来说就不会那么糟糕。
但是,您执行至少2次递归调用。因此,该计划以Ω(2^n)
而不是O(n)
运行。
动态编程通常像这样(伪代码):
calculate(input) {
if (value already calculated for input)
return previously calculated value
else
calculate and store value for input and return result
}
您可以通过将数组元素初始化为-1
(或0
,如果所有利润均为正数)来执行此操作:
Profit = new int[L.length];
Arrays.fill(Profit, -1); // no need to do this, if you are using 0
public int compute(int i) {
if (Profit[i] >= 0) { // modify the check, if you're using 0 for non-calculated values
// reuse already calculated value
return Profit[i];
}
...
Profit[i] = P[i] + (L[i]-L[i-1]< k ? 0 : compute(i-1));
^
Just ignores all positions before i-1
相反,您应该将利润用于至少k
英里之外的最后一个位置。
示例强>
k = 3
L 1 2 3 ... 100
P 5 5 5 ... 5
此处L[i] - L[i-1] < k
适用于所有i
,因此结果只有P[99] = 5
,但应为34 * 5 = 170
。
int[] lastPos;
public RestaurantProblem(int[] L, int[] P, int k) {
this.L = L;
this.P = P;
this.k = k;
Profit = new int[L.length];
lastPos = new int[L.length];
Arrays.fill(lastPos, -2);
Arrays.fill(Profit, -1);
}
public int computeLastPos(int i) {
if (i < 0) {
return -1;
}
if (lastPos[i] >= -1) {
return lastPos[i];
}
int max = L[i] - k;
int lastLastPos = computeLastPos(i - 1), temp;
while ((temp = lastLastPos + 1) < i && L[temp] <= max) {
lastLastPos++;
}
return lastPos[i] = lastLastPos;
}
public int compute(int i) {
if (i < 0) {
// no restaurants can be build before pos 0
return 0;
}
if (Profit[i] >= 0) { // modify the check, if you're using 0 for non-calculated values
// reuse already calculated value
return Profit[i];
}
int profitNoRestaurant = compute(i - 1);
if (P[i] <= 0) {
// no profit can be gained by building this restaurant
return Profit[i] = profitNoRestaurant;
}
return Profit[i] = Math.max(profitNoRestaurant, P[i] + compute(computeLastPos(i)));
}
答案 1 :(得分:0)
据我所知,问题可以用二维状态空间建模,我在目前的实现中找不到。对于每个(i,j) in
{0,...,n-1} times
{0,...,n-1}`让
profit(i,j) := the maximum profit attainable for selecting locations
from {0,...,i} where the farthest location selected is
no further than at position j
(or minus infinity if no such solution exist)
并注意重现关系
profit(i,j) = min{ p[i] + profit(i-1,lastpos(i)),
profit(i-1,j)
}
其中lastpos(i)
是距离起点最远的位置,但距离k
不到i
位置;上面的第一种情况对应于选择位置i
到解决方案中,而第二种情况对应于在解决方案中省略位置j
。通过评估profit(n-1,n-1)
可以获得整体解决方案;评估可以递归方式完成,也可以自下而上的方式填充二维数组,并在(n-1,n-1)
返回其内容。