2013-03-21 52 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

總是選擇可用的操作價值的最高分。