2

我正在尝试解决一个简单的 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];
}

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

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

谢谢!

4

2 回答 2

3

只需获取另一个字段来存储最佳步长,即-1、/2 或/3,如果获得最小路径是最佳的,可能只是使用1, 2,3作为指标。

例如,您正在比较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();
}
于 2012-11-19T04:44:39.937 回答
1

以下是如何检索路径:

    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 数组来存储它们。

于 2012-11-19T05:26:19.980 回答