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++。你应该删除。请重复你的回答。