我遇到了解决以下问题的麻烦。
假设一家公司需要在未来五年内拥有一台机器。每台新机器的价格为100,000美元。在运行的第i年运行机器的年度成本如下:C1 = 6000美元,C2 = 8000美元,C3 = 12,000美元。在交易之前,机器可以保持长达三年。这意味着机器可以在前两年保存或交易,并且必须在其年龄为三年时进行交易。 i年后的价值交易是t1 = 80,000美元,t2 = 60,000美元,t3 = 50,000美元。如果公司要在0年内购买新机器,公司如何在五年期间(第0年到第5年)最大限度地降低成本?
基于动态编程设计最佳解决方案。
可以使用树来表示此问题。这是图表。
现在我认为在上面的树中寻找最短路径会给我最优解。但我不知道该怎么做。这是我的问题,
欢迎任何其他建议。
伙计们,我想为这个问题提供一些指导和帮助。 (不要认为这是要求我完成作业的请求。)我已经找到了这个问题here的完整Java实现。但它不使用动态编程来解决问题。提前谢谢。
答案 0 :(得分:2)
该公司希望将成本降至5年以下。在0年级,他们将购买一台机器和一台机器。每年他们必须决定机器是否被保管或交易。为了达到最佳解决方案,我们必须在每年年底做出一系列选择。当我们做出每一个选择时,经常出现同样的子问题。 因此,我们到达一个位置,在该位置,给定的子问题可能来自多个部分选择集。在设计基于动态规划的最优解决方案时,我们可以通过将解决方案与子问题相结合来解决问题。
让阶段对应于每一年。州是该年机器的时代。决定是保留机器还是换新机器。假设机器在时间t为x岁,则将Ft(x)设为从时间t到时间5产生的最小成本。 基本情况:
由于我们必须在5年底交易机器F5(x)= - S [x]
保持现有机器最多3年:Ft(3)= N + M [0] + Ft + 1(0);吨≠0,1,2
def Fxy(自我,时间,年龄):
if self.Matrix[time][age]==None: <- Overlaping subproblems avoided if(time>5 or age>2): return 0 if time==5: self.Matrix[time][age]=T=self.S[age] self.Flag[time][age]='TRADE' elif time==0: self.Matrix[time][age]=K=self.N+self.M[0]+self.Fxy(time+1,time) self.Flag[time][age]='KEEP' elif time==3 and age==2: self.Matrix[time][age]=T=self.S[age]+self.N+self.M[0]+self.Fxy(time+1,0) self.Flag[time][age]='TRADE' else: T=self.S[age]+self.N+self.M[0]+self.Fxy(time+1,0) if age+1<len(self.Matrix[0]): K=self.M[age+1]+self.Fxy(time+1,age+1) else: K=self.M[age+1] self.Matrix[time][age]=min(T,K) if(self.Matrix[time][age]==T and self.Matrix[time][age]==K): self.Flag[time][age]='TRADE OR KEEP' elif(self.Matrix[time][age]==T): self.Flag[time][age]='TRADE' else: self.Flag[time][age]='KEEP' return self.Matrix[time][age] else: return self.Matrix[time][age]
通过绘制包含所有可能路径的决策树,可以实现最佳解决方案。采用最低成本路径。我们使用递归算法遍历每个树级别&amp;制作当前决策点发生的路径。 例如:当它遍历F1(0)时,它有“交易或保持”决定与它绑定。然后我们可以遍历两条可能的路径。当它遍历F2(1)时,因为它有'KEEP'决定然后递归地我们遍历F3(2),即正确的孩子。当'TRADE'遇到时,左边的孩子一直到达叶子。
def recursePath(self,x,y):
if(x==5):
self.dic[x].append(self.Flag[x][y])
return self.Flag[x][y]
else:
if(self.Flag[x][y]=='TRADE OR KEEP'):
self.recursePath(x+1,y)
self.recursePath(x+1,y+1)
if(self.Flag[x][y]=='KEEP'):
self.recursePath(x+1,y+1)
if(self.Flag[x][y]=='TRADE'):
self.recursePath(x+1,y)
self.dic[x].append(self.Flag[x][y])
return self.Flag[x][y]
答案 1 :(得分:1)
如果你想要像Dijkstra这样的东西,你为什么不做Dijkstra?你需要在图解释中改变一些东西,但它似乎非常可行:
Dijkstra将根据最低成本标准解决节点问题。将该标准定为“公司亏钱”。您还将解决Dijkstra中的节点,您需要确定节点究竟是什么。将节点视为时间和属性状态,例如第4年使用x岁的工作机器。在第0年,丢失的钱将是0,你将没有机器。然后添加所有可能的边/选择/状态转换,这里是“买一台机器”。您最终会在Dijkstra PQ(第1年,1岁的工作机器)上获得一个新节点,并且需要一定的费用。
从此,您可以随时出售机器(产生[年1,无机器]节点),购买新机器[第1年,新机器]或继续相同([2年级,机器年龄] 2])。你只需继续开发最短的路径树,直到第5年(或更多)你拥有你想要的一切。
然后你有一组节点[年i,机器年龄j]。为了在第一年为您的公司找到最佳选择,只需查看它的所有可能性(我认为它总是[年我,没有机器])来获得答案。
由于Dijkstra是一种全对最短路径算法,它为您提供了所有年份的最佳路径
编辑:java的一些伪代码 首先,您应该创建一个节点对象/类来保存您的节点信息。
Node{
int cost;
int year;
int ageOfMachine;
}
然后你可以添加节点并解决它们。确保您的PQ根据成本字段对节点进行排序。从根开始:
PQ<Node> PQ=new PriorityQueue<Node>();
Node root= new Root(0,0,-1);//0 cost, year 0 and no machine)
PQ.offer(root);
int [] best= new int[years+1];
//set best[0..years] equal to a very large negative number
while(!PQ.isEmpty()){
Node n=PQ.poll();
int y=n.year;
int a=n.ageOfMachine;
int c=n.cost;
if(already have a cost for year y and machine of age a)continue;
else{
add [year y, age a, cost c] to list of settled nodes;
//examine all possible further actions
//add nodes for keeping a machine and trading a machine
PQ.offer(new Node(cost+profit selling current-cost of new machine,year+1,1));
PQ.offer(new Node(cost,year+1,age+1);//only if your machine can last an extra year
//check to see if you've found the best way of business in year i
if(cost+profit selling current>best[i])best[i]=cost+profit selling current;
}
}
这些方面的某些内容将为您提供最佳实践,以达到最佳成本[i]
答案 2 :(得分:1)
我想我找到了一个更简单的动态程序解决方案。
建议成本(n)是在第n年出售时的全部成本。保持机器1年,2年,3年的成本是cost1,cost2,cost3(在这个问题上是26000,54000,76000)。
然后我们可以将问题分成这样的子问题:
**Cost(n)= MIN( Cost(n-1)+cost1, Cost(n-2)+cost2, Cost(n-3)+cost3 );**
所以我们可以用'自下而上的方式'来计算它,这只是O(n)。
我已经使用C:
实现并测试了它#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct costAndSell_S{
int lastSellYear;
int cost;
};
int operatCost[3]={6000,8000,12000};
int sellGain[3]={80000,60000,50000};
int newMachinValue=100000;
int sellCost[3];
struct costAndSell_S costAndSell[20];
void initSellCost(){
memset( costAndSell, 0, sizeof(costAndSell));
sellCost[0]=operatCost[0]+newMachinValue-sellGain[0];
sellCost[1]=operatCost[0]+operatCost[1]+newMachinValue-sellGain[1];
sellCost[2]=operatCost[0]+operatCost[1]+operatCost[2]+newMachinValue-sellGain[2];
costAndSell[0].cost=100000;
return;
}
int sellAt( int year ){
if ( year<0){
return(costAndSell[0].cost );
}
return costAndSell[year].cost;
}
int minCost( int i1, int i2, int i3 ){
if ( (i1<=i2) && (i1<=i3) ){
return(0);
}else if ( (i2<=i1) && (i2<=i3) ){
return(1);
}else if ( (i3<=i1) && (i3<=i2) ){
return(2);
}
}
void findBestPath( int lastYear ){
int i;
int rtn;
int sellYear;
for( i=1; i<=lastYear; i++ ){
rtn=minCost( sellAt(i-1)+sellCost[0], sellAt(i-2)+sellCost[1], sellAt(i-3)+sellCost[2]);
switch (rtn){
case 0:
costAndSell[i].cost=costAndSell[i-1].cost+sellCost[0];
costAndSell[i].lastSellYear=i-1;
break;
case 1:
costAndSell[i].cost=costAndSell[i-2].cost+sellCost[1];
costAndSell[i].lastSellYear=i-2;
break;
case 2:
costAndSell[i].cost=costAndSell[i-3].cost+sellCost[2];
costAndSell[i].lastSellYear=i-3;
break;
}
}
sellYear=costAndSell[lastYear].lastSellYear;
printf("sellAt[%d], cost[%d]\n", lastYear, costAndSell[lastYear].cost );
do{
sellYear=costAndSell[sellYear].lastSellYear;
printf("sellAt[%d], cost[%d]\n", sellYear, costAndSell[sellYear].cost );
} while( sellYear>0 );
}
void main(int argc, char * argv[]){
int lastYear;
initSellCost();
lastYear=atoi(argv[1]);
findBestPath(lastYear);
}
输出结果为:
sellAt[5], cost[228000]
sellAt[3], cost[176000]
sellAt[0], cost[100000]
答案 3 :(得分:0)
您提供的链接是动态编程 - 代码非常易于阅读。我建议你仔细看看代码,看看它在做什么。
答案 4 :(得分:0)
以下方法可能有用。
每年年底,您有两种选择。您可以选择交易或选择支付维护成本一年。除了第3年,你没有选择。你必须交易肯定。
这可以通过递归方法解决,您可以选择交易中的最低成本,而不是在特定年份进行交易。
表可以维持抵消,第n年(无交易),以便不需要重新计算值
答案 5 :(得分:0)
我认为它不能使用动态编程,因为我找不到最佳子结构和重叠子问题。 N年的成本取决于N-1,N-2和N-3年的行为。很难找到最佳的子结构。