以最有效的方式划分偶数

时间:2016-11-29 12:04:10

标签: c++ dynamic-programming

我需要一个用c ++编写的程序:

LOOP:

如果该数字是偶数除以2(n = n / 2) 如果它甚至不能执行以下操作之一: n + 1个 n-1个

LOOP ENDS

程序应该这样做直到n = 1。 但它应该以最有效和最快的方式做到这一点,我唯一的提示是我可以使用DP方法。 输出应该是用于计算该数字的操作数。 例如:

15-> 16-> 8-> 4-> 2-> 1输出:5

35-> 36-> 18-> 9-> 8-> 4-> 2-> 1输出:7

这里是我编写的代码,但它还没有完成,这是错误的,因为我无法弄清楚我应该如何在每一步中添加或减去:

#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
    int n;
    int h=0;
    int i=0;
    cout<<"Enter A Number:";
    cin >> n;
    int r=n;
    int q=n;
    cout<<r;
    L1: while ( r % 2 == 0)
    {
        for(int m=0;r>1 && m==0 ;)
        {   r=r / 2;h++;
        m=r%2;
    cout<<" => "<<r;
        }}
    while(r%2==1 && r>1)
        {r=r-1;cout<<" => "<<r;h++;
    goto L1;}
    cout<<endl;

    //**********************


    cout<<q;
    L2: while ( q % 2 == 0)
    {
        for(int m=0;q>1 && m==0 ;)
        {   q=q / 2;i++;
        m=q%2;
    cout<<" => "<<q;
        }}
    while(q%2==1 && q>1)
        {q=q+1;cout<<" => "<<q;i++;
    goto L2;}
    cout<<endl<<"First:"<<h<<endl<<"Second:"<<i<<endl;
system("pause");


}

4 个答案:

答案 0 :(得分:2)

如果您想要使用DP解决它

我会说:对于每个可能的值1&lt; = i&lt; N找到最佳步数。 我们使用优先级队列来执行此操作,我们在每次迭代中提取最高数字。这比长度为N的向量更有效,因为很多状态是不可达的(例如,在15例中i = 10)。

考虑起始状态是(15,0):15,零移动。 从这里你创建了两个新状态(8,2)和(7,2)因为每个你需要两个步骤(加/减+除法)。

提取(8,2):( 7,2)(4,3)

提取(7,2):( 4,3)(3,4)DP来了! (7,2)会创建状态(4,4)但你只在队列中保留相同状态的最小步数。

提取(4,3):( 2,4)(3,4)

提取(3,4):( 2,4)(1,6)

提取(2,4):( 1,5)

这就是解决方案的5个步骤。

35的步骤:

(35,0)---&gt;(18,2)(17,2)-----&gt; (17,2)(9,3)-----&gt;

(9,3)(8,4)----&gt; (8,4)(5,5)(4,5)----&gt; (5,5)(4,5)-----&gt;

(4,5)(3,7)(2,7)----&GT; (3,7)(2,6)-----&gt; (2,6)(1,9)----&gt; (1,7)

解决方案:7个步骤。

答案 1 :(得分:0)

看看这对你有帮助。

// Example program
#include <iostream>
#include <string>

int f (int n)
{
    int iterations = 0;

    while (n > 1)
    {
        if (n % 2 != 0)
        {
            std::cout << n << "->";
            ++n;
            if (n & (n - 1))
                n -= 2;

            ++iterations;
        }
        std::cout << n << "->";
        n >>= 1;
        ++iterations;
    }

    std::cout << n << "->";
    return iterations;
}

int main()
{
    std::cout << f(15) << std::endl;
    std::cout << f(41) << std::endl;
    std::cout << f(43) << std::endl;
}

答案 2 :(得分:0)

对于动态编程的使用,你应该进行递归以获得问题的子解决方案,然后自己解决问题。您还必须使用内存结构来保存此类子解决方案的结果。

#include <deque>
#include <iostream>

using namespace std;

int solve(deque<int>& solution, int number) {
    if(number >= solution.size())           // resize to fit
        solution.resize(number + 1, -1);
    if(number == 1)                         // special case for number 1
        return solution[number] = 0;
    if(solution[number] != -1)              // if already calculated
        return solution[number];
    if(number % 2 == 0)                     // n=n/2
        return solution[number] = solve(solution, number/2) + 1;
    int solutionA = solve(solution, number + 1);    // n++
    int solutionB = solve(solution, number - 1);    // n--
    return solution[number] = std::min(solutionA, solutionB) + 1; // best of n++,n--
}

int main() {
    deque<int> solution;
    cout << solve(solution, 35);
}

我不确定代码是否可行。

答案 3 :(得分:0)

这是我的递归解决方案,针对DP示例验证了高达2097152。 它的基础是使用最后两位的值来确定最佳操作。如果最后一位是0,我们总是分开。如果最后两位是11,我们总是递增,因为这转换为100,这启用了两个连续的除法运算。 如果最后两位是01,我们递减,因为这给我们的下一个操作两个连续的除法运算与递增,这给了我们10

角落的情况是数字3,其中3 - >在推广到4时需要2。

我怀疑你可以通过扫描位模式来进一步优化它,以确定所需的操作数量。即每个零需要一个div运算,并且一组1可以通过一次加法变为零。

#include <cstdint>

int solve_algorithmically(std::uint64_t number)
{
    // If 1 there is nothing to do.
    if (number <= 1)
        return 0;

    // Nasty hack to get around the case where number=3 & 3 == 3 will cause increment 
    if (number == 3)
        return solve_algorithmically(number - 1) + 1;

    // If we have an even number (0 in LSB)
    if ((number & 1) == 0)
        return solve_algorithmically(number / 2) + 1;

    // If we have two consecutive 1's i.e. (...11) then increment as this wil give us two zeroes.
    // The exception is the root case 3 where decrement wins.
    if ((number & 3) == 3)
        return solve_algorithmically(number + 1) + 1;

    // The only other case ends last two bits = 01
    return solve_algorithmically(number - 1) + 1;
}

int main() {
    for (auto i = 1; i < 2097152; i++)
    {
        int alg = solve_algorithmically(i);
    }
}