【问题标题】:dynamic algorithm to find optimal solution寻找最优解的动态算法
【发布时间】:2019-04-09 04:56:08
【问题描述】:

考虑一个无聊的游戏,白色和红色方块按如下顺序排列:

(开始 w w w w w w r r w w w w r w r w r w 结束)

w = 白色。 r = 红色。

有 3 个按钮。 绿色按钮:移动 5 步。 黄色按钮:移动 3 步。 蓝色按钮:移动 3 步。

游戏规则: - 如果玩家落在红色方块上输了。 - 第一个玩家完成游戏获胜。 - 允许在白色方块上着陆。

贪心算法:

x = 0 
steps = 0
stop = false
while (....)
if a[x+5] is white then
 push the green buttton and x= x+5, steps++
if a[x+3] is white then
 push the yellow buttton and x= x+3, steps++
if a[x+2] is white then
 push the blue buttton and x= x+2, steps++
else stop = true

必需:赢得比赛的最少步数。

按照上面的贪心算法,解将是 552225,而最优解是 33555。

我的问题是如何应用动态算法找到最优解?

【问题讨论】:

    标签: algorithm dynamic


    【解决方案1】:

    您想要做的是生成一个包含最小成本和最佳先前移动的数组。您从头到尾填写它,然后从头到尾阅读最佳解决方案。像这样:

    min_cost = [infinite for all steps]
    arriving_move = [none for all steps]
    For each i in 0 to steps-1:
        if square[i] = 'r':
            pass
        else:
           for j in 2, 3, 5:
               if i <= j:
                   if min_cost[i-j] + 1 < min_cost[i]:
                       min_cost[i] = min_cost[i-j] + 1
                       arriving_move[i] = j
    reversed_answer = []
    i = steps-1
    while arriving_move[i] is not none:
        reversed_answer.append(arriving_move[i])
        i = i - arriving_move[i]
    answer = reversed(reversed_answer)
    

    请注意,这将找到一个最佳游戏,您可以直接到达终点。因此,在您的示例中,移动将出现 33553。

    如果您对“超标”没问题,则必须在末尾添加一个带有自己特殊规则的特殊结束节点。

    【讨论】:

      【解决方案2】:

      想法:向后思考。假设你在i。到达此单元格的选项有哪些?

      // Assume cell[i] = min number of moves to last cell starting from this cell
      
      cell[n] = 0 //finish cell
      cell[0..n-1] = ∞
      
      for i = n to 1
        cell[i-1] = min(cell[i-1], cell[i]+1) //if cell[i-1] not red
        cell[i-3] = min(cell[i-1], cell[i]+1) //if cell[i-3] not red
        cell[i-5] = min(cell[i-1], cell[i]+1) //if cell[i-5] not red
      

      最后,cell[0] 的值显示了完成游戏所需的最少步数。

      【讨论】:

        【解决方案3】:

        要到达终点,您应该先降落在任一上

        finish - 5finish - 3finish - 2 然后再点击 1 次按钮即可到达 finish

        这个的递归公式:

        minSteps(end) = 1 + Math.min( minSteps(end-5), Math.min(minSteps(end-2), minSteps(end-3)) )

        您可以像在 (Java) 中那样使用 memoization 编写代码:

        private static int minSteps( int start, int end, String s ) {
            if ( end < start ) return Integer.MAX_VALUE;
            if ( end == start ) return 0;
            if ( s.charAt(end) == 'r' ) {
              dp[end] = Integer.MAX_VALUE;
              return dp[end];
            }
            if ( dp[end] != -1 ) return dp[end];
            int stepTwo = minSteps( start, end - 2, s );
            int stepThree = minSteps( start, end - 3, s);
            int stepFive = minSteps( start, end - 5, s );
            int min = Math.min( Math.min( stepTwo, stepThree ), stepFive );
            if ( min != Integer.MAX_VALUE ) {
              dp[end] = 1 + min;
            } else {
              dp[end] = min;
            }
            return dp[end];
        }
        

        对于输入:w w w w w w r r w w w w r w r w r w,生成的 dp 数组将是:

        [-1, 2147483647, 1, 1, 2, 1, 2147483647, 2147483647, 2, 3, 2, 3, 2147483647, 3, 2147483647, 3, -1, 4] 答案是 4:18 -&gt; 16 -&gt; 11 -&gt; 6 -&gt; 1

        然后您可以按照dp 数组从头开始构建跳跃。

        【讨论】:

          猜你喜欢
          • 2013-07-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-25
          • 1970-01-01
          • 2023-03-10
          • 2011-03-12
          • 1970-01-01
          相关资源
          最近更新 更多