【问题标题】:How to trace path in a simple dynamic programming prob?如何在简单的动态规划问题中跟踪路径?
【发布时间】:2012-11-19 04:34:45
【问题描述】:

我正在尝试解决一个简单的 DP 问题:

给定一个正整数 n,您可以执行以下 3 个步骤中的任何一个。 1) 减去 1。
2) 如果能被 2 整除,则除以 2。
3) 如果能被 3 整除,则除以 3。
请找出 n 到 1 的最小步数并打印出来。如果有多个解决方案以相同的步骤数实现目标,请打印出所有这些解决方案。 (如果很难,至少打印出这些解决方案之一)。


获得最少的步数并不难。只需像这样应用自下而上的 DP 解决方案:

public int getMinSteps(int n) {
int[] dp = new int[n+1];

int i;
dp[1] = 0; 

for( i = 2 ; i < = n ; i ++ ) {
dp[i] = 1 + dp[i-1];
if(i%2==0) dp[i] = min( dp[i] , 1+ dp[i/2] );
if(i%3==0) dp[i] = min( dp[i] , 1+ dp[i/3] );
}
return dp[n];
}

但是,我无法解决打印路径部分。在高层次上,我认为我需要在每个层次上停止“行动”,确定一个最低限度?

希望我能在这里得到一些好的建议或解决方案。

谢谢!

【问题讨论】:

    标签: java algorithm dynamic-programming


    【解决方案1】:

    只要得到另一个字段来存储最优步长,即-1、/2、或/3,如果最优则得到最小路径,可能只是使用123作为指标.

    例如,您正在比较a = 1 + dp[i-1]b = 1 + dp[i/2]c = 1 + dp[i/3]。如果a 是最小值,那么您知道该数字应该为-1。将步骤存储为1。稍后,您只需跳转到i-1 的字段即可找到下一步,直到到达起点,即1。


    更新:

    如果要打印所有路径,则必须存储所有最佳步骤,并打印所有组合。

    具体来说,您可以使用 -1、/2、/3 三个布尔字段来存储是否有任何最优路径经过某个数字。之后,您可以递归地打印所有组合,就像遍历一棵树一样。

    int[] dp; // for minimum steps
    bool[] gominus1;
    bool[] godivideby2;
    bool[] godivideby3;
    List<Integer> steps;
    
    PrintAllPath(int n) {
        if(n == 1) {
            // print steps
            return;
        }
        steps.push_back(n);
        if(gominus1[n]) {
            PrintAllPath(n - 1);
        }
        if(godivideby2[n]) {
            PrintAllPath(n / 2);
        }
        if(govidivideby3[n]) {
            PrintAllPath(n / 3);
        }
        steps.pop_back();
    }
    

    【讨论】:

    • 感谢您的建议。我想我需要找到一个合适的数据结构来存储这些步骤,因为可能有很多步骤。更复杂的是,可能有多个步骤组合。
    • @user1660652 这有点简单。请参阅答案中的更新。
    【解决方案2】:

    这是检索路径的方法:

        public static int getMinSteps(int n) {
        int[] dp = new int[n + 1];
        String[] path = new String[n+1];
        int i;
        dp[1] = 0;
        path[1] = "end";
    
        for (i = 2; i <= n; i++) {
            dp[i] = 1 + dp[i - 1];
            if (i % 2 == 0) {
    
                if(dp[i] < 1 + dp[i/2]){
                    path[i] = "sub 1," + path[i-1];
                }
                else {
                   path[i] = "div by 2," + path[i/2];
                }
    
                dp[i] = min(dp[i], 1 + dp[i / 2]);
    
            }
    
            if (i % 3 == 0) {
    
                 if(dp[i] < 1 + dp[i/3]){
                    path[i] = "sub 1," + path[i-1];
                }
                else {
                   path[i] = "div by 3," + path[i/3];
                }
    
                dp[i] = min(dp[i], 1 + dp[i / 3]);
            }
    
            if( i % 3 != 0 && i % 2 != 0) {
                 path[i] = "sub 1," + path[i-1];
            }
    
        }
        System.out.println("number of steps = "+dp[n]+",path = "+path[n]);
        return dp[n];
    }
    

    这是打印单个路径。要打印所有路径,您需要跟踪 dp[i] 的所有最小可能方式。所以你需要一个 String 的二维数组来存储它们。

    【讨论】:

    • 谢谢 - 如果只有一个优化的解决方案,我认为这将是完美的。但是,对于有两个或更多优化解决方案的情况,它只会打印出其中一个。例如,如果 n=7,那么我们可以这样做: (1) sub 1, div 2, div 3;或 (2) sub 1,div 3,div 2。
    • 是的,要拥有所有路径,您需要使用变量路径的二维数组并将所有最佳组合存储在那里。
    猜你喜欢
    • 2011-11-28
    • 2020-10-03
    • 1970-01-01
    • 2011-10-17
    • 2012-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多