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;
}