2013-03-21 59 views
5

我可以从“动作”列表中进行选择,每秒执行一次。列表中的每个动作都有一个表示它值多少的数值,还有一个表示其“冷却时间”的值 - 在再次使用该动作之前,我必须等待的秒数。该列表可能是这个样子:优化冷却时间动作顺序的算法

  • 动作A的值为1和2秒
  • 冷却时间
  • 行动B具有1.5的值,3秒的冷却时间
  • 行动C具有的2值和5秒
  • 冷却时间
  • 行动d具有值3和10秒

所以在这种情况下一个冷却时间,顺序ABA将具有的合计值(1 + 1.5 + 1)= 3.5,这是可以接受的,因为第一个u A发生在1秒内,A的最终使用发生在3秒,然后两者之间的差值大于或等于A的冷却时间,2秒。 AAB的命令不起作用,因为你只需要做A就可以了,而不是冷却时间。

我的问题是试图优化操作的使用顺序,最大限度地提高一定数量操作的总价值。显然,如果你只使用一个动作,最佳顺序是做动作D,结果总值为3.两个动作的最大值来自做CD或DC,结果总值为5。当你执行10或20或100次总行动时会变得更加复杂。我无法找到一种方法来优化操作的顺序,而不会蛮横强迫它,这使得它对于要优化顺序的操作的总数具有指数级的复杂性。过去总共有15个变得不可能。

那么,有没有什么方法可以找到最佳时间,而且复杂性更低?有没有研究过这个问题?我想可能有某种类型的加权图类型的算法可以解决这个问题,但我不知道它是如何工作的,更不用说如何实现它了。

对不起,如果这是令人困惑的 - 这有点奇怪的概念,我找不到一个更好的方式来构建它。

+1

最多可以有多少种不同类型的动作? – aram90 2013-03-21 21:01:29

+0

实际上不会超过12. – user2196830 2013-03-21 21:13:06

回答

1

编辑:重读你的问题多一点后,我看到加权调度算法将需要调整,以适应你的问题陈述;在我们的案例中,我们只想将那些重叠的动作从与我们选择的动作类别相匹配的集合中取出,并将那些在相同时间点开始的动作重叠起来。 IE如果我们选择a1,我们想从集合中删除a2b1,但不是b2

这看起来与在深度in this pdf中讨论的加权调度问题非常相似。实质上,权重是你行动的价值,间隔是(starttime,starttime + cooldown)。动态编程解决方案可以进行记忆,使其在O(nlogn)时间内运行。唯一困难的部分是修改你的问题,使它看起来像加权区间问题,这使得我们可以利用预定的解决方案。因为你的时间间隔没有设置开始和结束时间(IE你可以选择何时开始某个动作),我建议列举所有给定动作的所有可能的开始时间,假设一些设定的时间范围,然后使用这些静态开始/结束时间与动态编程解决方案。假设你只能在整秒内开始一个动作,你可以运行动作A的间隔(0-2,1-3,2-4,...),动作B的(0-3,1-4,2) -5,...),间隔(0-5,1-6,2-7,...)的动作C等。然后,可以使用联合行动的集合,以获得问题的空间,看起来像原来的加权间隔问题:

|---1---2---3---4---5---6---7---| time 
|{--a1--}-----------------------| v=1 
|---{--a2---}-------------------| v=1 
|-------{--a3---}---------------| v=1 
|{----b1----}-------------------| v=1.5 
|---{----b2-----}---------------| v=1.5 
|-------{----b3-----}-----------| v=1.5 
|{--------c1--------}-----------| v=2 
|---{--------c2---------}-------| v=2 
|-------{-------c3----------}---| v=2 
etc... 
+0

不幸的是,通过强制枚举所有可能的动作开始时间和结束时间,解决方案不再是'O(n lg n)'。 – 2013-03-21 22:03:59

+0

你说得对,我忘了补充一点。虽然给了一个时间跨度和行动的数量,这不是一次性增加cn吗? – ryanbwork 2013-03-21 22:06:10

+0

那么,如果最大突发时间为'm',那么从技术上讲,对于每个动作都会有'm/action.cooldown'。假设所有动作都具有相同的'n'的冷却时间,那么将会是'n * m/action.cooldown'的行。 – 2013-03-21 22:07:37

3

编辑:下面是一个使用高改进Dijkstra算法的妥善解决办法:

Dijkstra算法是用于找到最短路径,给定一个映射(一个Graph Abstract),它是一系列节点(通常是位置,但是对于这个例子,假设它们是Actions),它们通过弧相互连接(在这种情况下,而不是距离,每个弧将有一个'值')

这里是本质上的结构。

Graph{//in most implementations these are not Arrays, but Maps. Honestly, for your needs you don't a graph, just nodes and arcs... this is just used to keep track of them. 
node[] nodes; 
arc[] arcs; 
} 
Node{//this represents an action 
arc[] options;//for this implementation, this will always be a list of all possible Actions to use. 
float value;//Action value 
} 
Arc{ 
node start;//the last action used 
node end;//the action after that 
dist=1;//1 second 
} 

我们可以使用这个数据类型,使地图的所有可行的方案,采取以获得最佳的解决方案的基础上,着眼于最终总每个路径的。因此,在寻找模式之前越多秒,您就越有可能找到非常优化的路径。

地图上的每一段道路都有一段距离,它代表着它的价值,每一站都是一秒钟的标记,因为那时候是决定去哪里的地方(什么动作执行)下一步。 为了简单起见,假设A和B是唯一可行的选项。 na表示没有操作,因为没有操作可用。 如果你是旅游4秒(高量,效果越好),你的选择是......

A->na->A->na->A 
B->na->na->B->na 
A->B->A->na->B 
B->A->na->B->A 
... 

有更多的太多,但我已经知道,最优路径是B-> A - > na-> B-> A,因为它的价值是最高的。因此,处理这些动作组合的最佳模式是(至少在分析它4秒之后)B-> A> na-> B-> A这实际上是一个相当简单的递归算法。

/* 
    cur is the current action that you are at, it is a Node. In this example, every other action is seen as a viable option, so it's as if every 'place' on the map has a path going to every other path. 
    numLeft is the amount of seconds left to run the simulation. The higher the initial value, the more desirable the results. 

This won't work as written, but will give you a good idea of how the algorithm works. 
*/ 
function getOptimal(cur,numLeft,path){ 
    if(numLeft==0){ 
    var emptyNode;//let's say, an empty node wiht a value of 0. 
    return emptyNode; 
    } 
    var best=path; 
    path.add(cur); 
    for(var i=0;i<cur.options.length;i++){ 
    var opt=cur.options[i];//this is a COPY 
    if(opt.timeCooled<opt.cooldown){ 
     continue; 
    } 
    for(var i2=0;i2<opt.length;i2++){ 
     opt[i2].timeCooled+=1;//everything below this in the loop is as if it is one second ahead 
    } 
    var potential=getOptimal(opt[i],numLeft-1,best); 
    if(getTotal(potential)>getTotal(cur)){best.add(potential);}//if it makes it better, use it! getTotal will sum up the values of an array of nodes(actions) 
    } 
    return best; 
} 
function getOptimalExample(){ 
    log(getOptimal(someNode,4,someEmptyArrayOfNodes));//someNode will be A or B 
} 

End edit。

我对这个问题有点困惑,但...

如果你的动作数量有限,仅此而已,那么总是挑最值的动作,除非冷却时间也没有还没有见过。

听起来像是你想这样的事情(在伪代码):

function getOptimal(){ 
var a=[A,B,C,D];//A,B,C, and D are actions 
a.sort()//(just pseudocode. Sort the array items by how much value they have.) 
var theBest=null; 
for(var i=0;i<a.length;++i){//find which action is the most valuable 
    if(a[i].timeSinceLastUsed<a[i].cooldown){ 
     theBest=a[i]; 
     for(...){//now just loop through, and add time to each OTHER Action for their timeSinceLastUsed... 
      //... 
     }//That way, some previously used, but more valuable actions will be freed up again. 
     break; 
    }//because a is worth the most, and you can use it now, so why not? 
} 
} 
+0

这就是我最初的尝试,但似乎最佳解决方案将涉及在较慢的之间使用大量快速冷却动作,而这些动作不会由高到低来捕捉。 – user2196830 2013-03-21 22:14:47

+0

我认为*会*被捕获,实际上;任何时候没有任何缓慢的行动可用,你会采取更快的行动。如果高价值行动足够缓慢,您会看到很多这些快速行动;否则,你不会。 – 2013-03-22 00:29:37

+0

当你有数量有限的不同动作可用时,只要在最坏的情况下做得最好,特别是当最好的时间有更长的冷却时间时,最终会导致你无法完成任何动作。以我的主要帖子为例,如果你在前四秒完成了DCBA,那么你在5秒内就没有剩下的事情了。我们的目标是能够每一秒都做出一个动作,所以相反,像ABACABADABACB这样符合冷却要求的东西会更好。对不起,如果我做了一个糟糕的工作解释我想要什么。 – user2196830 2013-03-22 02:06:17

0

总是选择可用的操作价值的最高分。