Python 找到达到n所需的最小步骤

Python 找到达到n所需的最小步骤,python,algorithm,dynamic-programming,Python,Algorithm,Dynamic Programming,我试图解决一个动态规划问题,如下所示,但无法解决它 您将获得一个原语计算器,该计算器可以使用当前数执行以下三个操作要解决此DP,您必须构建一个表,列出获得n所需的最少步骤数(如果有一个、两个或所有操作可用)。您将从左到右,从上到下创建它,即从1到n,将1添加到mul 3。当你往下走的时候,更多的操作是可用的 单元格值仅取决于其上方的值(如果可用)和左侧的atmax 3值,例如(n=6),(mul 3)单元格将仅取决于(n=6),(mul 2)和(n=2)(mul 3),(n=3)(mul 3),

我试图解决一个动态规划问题,如下所示,但无法解决它


您将获得一个原语计算器,该计算器可以使用当前数执行以下三个操作要解决此DP,您必须构建一个表,列出获得n所需的最少步骤数(如果有一个、两个或所有操作可用)。您将从左到右,从上到下创建它,即从1到n,将1添加到mul 3。当你往下走的时候,更多的操作是可用的

单元格值仅取决于其上方的值(如果可用)和左侧的atmax 3值,例如(n=6),(mul 3)单元格将仅取决于
(n=6),(mul 2)
(n=2)(mul 3)
(n=3)(mul 3)
(n=5)(mul 3)
。然后,您将比较这些值,操作后取较小者,您将输入该值,因此您将比较
(n=2)(mul 3)+1
(n=3)(mul 3)+1
(n=5)(mul 3)+1
(n=6)(mul 2)
,然后取较小者输入该值

因为给定了n=1,所以第一列的所有值都为零

对于n=2,其值将取决于n=1的值。您可以“加1”或“乘2”(1步),两者都有效。所以这列的所有值都是0+1=1

对于n=3,其值将取决于n=1(因为1=3的1/3)和n=2的值。如果您只能“加1”或“乘2”,那么您将选择将1添加到n=2,这样总步骤1+1=2。但是如果你也可以乘以3,你只需要一步,所以0+1=1。因为1小于2,所以将1作为该值。所以n=3的条目是2,2,1

对于n=4,它将取决于n=3(加1)和n=2(MUL2)。所以值是3,2,2

对于n=5,它将取决于n=4(加1)。所以值是4,3,3

因此,达到n=5的最小步骤为3

最终表格:

    1  2  3  4  5
add 1  0  1  2  3  4
mul 2  0  1  2  2  3
mul 3  0  1  1  2  3

该算法分为两部分。第一个在主功能中,第二个在
optVal
功能中

第一部分构建
缓存
列表,其中
缓存[i]
包含从
0
i
所需的最少步骤数,在每个步骤中应用三种可能的操作之一:
+1
*2
*3
。此列表是您所了解的矩阵的一维情况

当计算
cache[i]
时,所有低于
i
的索引都已计算完毕。人们可以通过三种可能的方式访问
i
,因此最多需要检查
i
的三种可能来源,即
cache
的元素:
i-1
i//2
i//3
,但
i//2
只有在
i
为偶数时,和
i//3
仅当
i
可以除以3时。比较
cache
的这些元素,赢家的内容(由于到达
i
的额外步骤)增加1,存储在
cache
中。此过程通过将
0
放入
缓存[0]
来启动。最后,
cache[target]
将包含从
0
开始到达
target
的最少步骤数(这比从
1
开始到达目标的步骤数多1步,这就是问题的说明方式–请注意,您只能应用
+1
操作从
0
移出)

现在,如果我写了代码,我可能会存储每个
缓存[I]
的“父操作”或“获胜操作”以及到达那里的步骤数(顺便说一句,那些
math.inf
并不是真正需要的,因为由于
+1
操作,
i
总是有有限的步数。)作者的方法是从每个
缓存[i]的可能父级(最多3个)的内容推断出这些信息
需要检查。在这两种情况下,“祖先”链都必须从
缓存[target]
开始向后重建,这就是
optVal()中发生的情况

optVal(),因为在每次迭代中,您所拥有的信息是达到某个目标数所需的最小步数。知道了这一点,您可以查看1、2或3个可能的父级,以检查哪一个正好包含减去1的步骤数。通过测试的是实际的父级,因此您可以继续向后构建链repl与家长一起设定目标。

\include
#include <bits/stdc++.h>

using namespace std;
int rec(vector<int> &dp,int n)
{
    if(n==1) return 0;
    if(dp[n]!=INT_MAX) return dp[n];
    return dp[n]=min({1+rec(dp,n-1),(n%2==0)?1+rec(dp,n/2):INT_MAX,(n%3==0)?1+rec(dp,n/3):INT_MAX});
}
string genseq(vector<int> &dp, int n){
    string res="";
    while(n>1)
    {
        res=to_string(n)+" "+res;
        if(dp[n-1]==(dp[n]-1)) n--;
        else if(n%2==0&&( dp[n/2]==dp[n]-1)) n/=2;
        else if(n%3==0&&( dp[n/3]==dp[n]-1)) n/=3;
    }
    return "1 "+res;
}
int main()
{
    int n;
    cin>>n;
    vector<int> dp(n+1,INT_MAX);
    dp[0]=0;
    dp[1]=0;
    std::cout << rec(dp,n) << std::endl;
    std::cout << genseq(dp,n) << std::endl;
    return 0;
}
使用名称空间std; int rec(矢量和dp,int n) { 如果(n==1)返回0; 如果(dp[n]!=INT_MAX)返回dp[n]; 返回dp[n]=min({1+rec(dp,n-1),(n%2==0)?1+rec(dp,n/2):INT_MAX,(n%3==0)?1+rec(dp,n/3):INT_MAX}); } 字符串genseq(矢量和dp,整数n){ 字符串res=“”; 而(n>1) { res=to_字符串(n)+''+res; 如果(dp[n-1]==(dp[n]-1))n--; 如果(n%2==0&(dp[n/2]==dp[n]-1))n/=2; 如果(n%3==0&(dp[n/3]==dp[n]-1))n/=3; } 返回“1”+res; } int main() { int n; cin>>n; 向量dp(n+1,INT_MAX); dp[0]=0; dp[1]=0;
STD::问题陈述与编辑距离相似。我希望它能帮助你:伟大的解释,我终于能够理解它。谢谢你这样做!你误解了问题:OP没有要求另一个解决方案,而是解释他所展示的一个。还有:这个问题有一个Python标签,而不是C++。你应该删除。请重复你的回答。