Algorithm 乘以/加上初始编号以获得目标编号
假设我有一个目标编号Algorithm 乘以/加上初始编号以获得目标编号,algorithm,Algorithm,假设我有一个目标编号n,例如5,我总是从数字1开始,我必须*2或*3或+1,直到我到达n。所以在这种情况下,我将*2两次,然后+1得到5 我应该找到达到目标值的最少操作数。我看到了一个类似的问题,但这需要固定数量的步骤,而我必须找出最少的步骤。关于如何解决这个问题,有什么建议吗 这是一个家庭作业问题。你考虑过人工智能方法吗 将您的问题想象为树中的搜索:根是1,树中的每个节点X都有3个子节点:2*X,3*X,X+1 您可以构建整个树(每个节点X,其中X>n不应该有更多的子节点),并使用查找从根节点
n
,例如5,我总是从数字1开始,我必须*2
或*3
或+1
,直到我到达n
。所以在这种情况下,我将*2
两次,然后+1
得到5
我应该找到达到目标值的最少操作数。我看到了一个类似的问题,但这需要固定数量的步骤,而我必须找出最少的步骤。关于如何解决这个问题,有什么建议吗
这是一个家庭作业问题。你考虑过人工智能方法吗 将您的问题想象为树中的搜索:根是1,树中的每个节点X都有3个子节点:2*X,3*X,X+1
您可以构建整个树(每个节点X,其中X>n不应该有更多的子节点),并使用查找从根节点到具有值n的节点的最短路径,或者在图形不适合内存的情况下使用算法。这可以被视为搜索或DP问题(是的,本质上它们都与状态转换相关),关键点是定义搜索状态条件,假设
n
为正,这里我们定义f[i]=inf,inf是一个非常大的整数
表示数i
不可及,f[i]=k,k>=0
意味着至少可以通过k
步骤达到编号i
如果
n
不是那么大,我们可以使用一个数组来存储从1到n的每个数字的最小步长。初始值是f[1]=0
和f[i]=inf,2我认为这里的方法是向后工作。从n
开始,尝试减少最多的操作,然后是列表中的第二个操作,等等。代码可能如下所示:
string actions = "";
int i = n, count = 0;
while (i > 1)
{
count++;
if (i % 3 == 0)
{
i = i / 3;
actions = "*3 " + actions;
continue;
}
if (i % 2 == 0)
{
i = i / 2;
actions = "*2 " + actions;
continue;
}
i--;
actions = "+1 " + actions;
}
基本上,我们的想法是尽可能快地到达n
。我不确定这是否是最少的步骤,但这看起来确实是一个好的开始。这将为您提供保证的最短路径
static int result(int a, int b){
int answer = 0;
while (a < b){
if (b % 3 == 0 && b / 3 >= a){
b = b / 3;
answer++;
}
else if ((b - 1) % 3 == 0 && (b - 1) / 3 >= a){
b = b - 1;
b = b / 3;
answer += 2;
}
else if (b % 2 == 0 && b / 2 >= a){
b = b / 2;
answer++;
}
else{
b = b - 1;
answer++;
}
}
return answer;
}
静态整数结果(整数a、整数b){
int-answer=0;
while(a=a){
b=b/3;
回答++;
}
如果((b-1)%3==0&&(b-1)/3>=a){
b=b-1;
b=b/3;
答案+=2;
}
否则如果(b%2==0&&b/2>=a){
b=b/2;
回答++;
}
否则{
b=b-1;
回答++;
}
}
返回答案;
}
我们能把像15
这样的数字写成(2*2+1)吗*3
或者它必须是2*2*3+1+1+1
?这里的n
有多大?如果是几十万,那么你可能仍然可以通过DP方法逃脱,最多是十万。@lrr前者应该可以。@maregor请查看我关于如何输出获取目标操作的最新答案。这不是bad想法,但如果n
足够大,这可能是一个很长的计算任务。…@shapiro.yaacov有另一个不到O(n)复杂度的想法吗?你建议的不是O(n)。请看我的答案。@shapiro.yaacov我明白你的意思。但是正如你在帖子中建议的,最快的方法并不总是最短的(最少的步数)例如,你的28步代码:((1*2*3)+1)*2*2->5步
然而,最理想的是:(1*3*3)+1->4步
你是100%正确的。这个问题是一个典型的例子,DP优于暴力。请看@coderz的答案。我不确定这个算法是否能给出最好的结果,但在我看来这很好:)这是正确的答案。我认为它是一个在节点之间有边的图,表示+1、*2或*3,运行一个S=1和T=n的BFS+从我这里得到1。@Lrrr算法可能不是最好的性能,但它总能得到正确的答案:)例如:给定n=10,你的方式–>10/2=5-1=4/2=2/2=1(4个步骤)。但最佳方法是–>10-1=9/3=3/3=1(3步)。
string actions = "";
int i = n, count = 0;
while (i > 1)
{
count++;
if (i % 3 == 0)
{
i = i / 3;
actions = "*3 " + actions;
continue;
}
if (i % 2 == 0)
{
i = i / 2;
actions = "*2 " + actions;
continue;
}
i--;
actions = "+1 " + actions;
}
static int result(int a, int b){
int answer = 0;
while (a < b){
if (b % 3 == 0 && b / 3 >= a){
b = b / 3;
answer++;
}
else if ((b - 1) % 3 == 0 && (b - 1) / 3 >= a){
b = b - 1;
b = b / 3;
answer += 2;
}
else if (b % 2 == 0 && b / 2 >= a){
b = b / 2;
answer++;
}
else{
b = b - 1;
answer++;
}
}
return answer;
}