【问题标题】:How can I develop the exact recurrence for this?我怎样才能为此制定确切的复发?
【发布时间】:2015-08-07 16:22:56
【问题描述】:

N 个建筑物排成一排,从左到右编号为 1 到 N。 蜘蛛侠在 1 号楼,想到达 N 号楼。 如果 i

输入:

第一行包含 N,建筑物的数量。 下一行包含 N 个空格分隔的整数,表示数组高度。

输出:

打印一个整数,上面问题的答案。

所以,我想到了这样的事情:

int calc(int arr[], int beg, int end, )
{
    //int ans = INT_MIN;
    if (beg == end)
        return 0;
    else if (beg > end)
        return 0;
    else
    {
        for (int i = beg+1; i <= end; i++ ) // Iterate over all possible combinations
        {
            int foo = arr[i] - arr[beg]; // Check if power of two or not
            int k = log2(foo);
            int z = pow(2,k);
            if (z == foo) // Calculate the minimum value over multiple values
            {
                int temp = calc(arr,i,end);
                if (temp < ans)
                    temp = ans;
            }
        }
    }
}

以上是我要解决的问题,链接如下:https://www.codechef.com/TCFS15P/problems/SPIDY2 但是,上面的递归并不完全正确。我是否也必须在其中传递answer 的值?

【问题讨论】:

  • 您是在寻找运行时(重复)还是算法?
  • 不,我正在寻找这个问题的递归解决方案。我尝试像上面那样开发它,但我真的做不到。
  • 与其使用log2()pow(),不如使用Integer.bitCount(foo) == 1) 来测试foo 是否是2 的幂。另外,你的意思是不是“递归解决方案”而不是“精确重复”?最后,calc() 的第四个参数是怎么回事,或者end 后面的逗号是错字吗?
  • "Recurrence" 不是您要找的词。
  • 仔细阅读问题陈述。它说某事应该是 2 的幂。看看代码。 2的幂在哪里检查?检查是否正确?还有这个来自不同步骤的能量小问题。需要总结一下。你在哪里做这个?

标签: algorithm


【解决方案1】:

我们可以从任何(n-2^0),(n-2^1),(n-2^2)... 建筑物到达第n 栋建筑物。所以我们需要从 1 开始处理建筑物。对于每个建筑物 i,我们计算从任何早期建筑物 j 到达那里的成本,其中 i-j 是 2 的幂并取最小成本。

int calc(int arr[],int dp[],int n) {
    // n is the target building
    for(int i=1; i<=n; i++) dp[i]=LLONG_MAX;  //initialize to infinity
    dp[1]=0;  // no cost for starting building
    for(int i=2; i<=n; i++) {
        for(int j=1; i-j>=1; j*=2) {   
            dp[i]=min(dp[i], dp[i-j]+abs(arr[i]-arr[i-j]));
        }
    }
    return dp[n];
}

时间复杂度为 O(n*log(n))。

【讨论】:

  • 我对您的答案投了赞成票,但您的程序中仍然存在一个小错误。您没有考虑“j-i 是 2 的幂”的要求。在您的代码中,j = 8 和 i = 3 将导致 5 作为 j-i 值。
【解决方案2】:

首先,您正在检查错误数量的 2 次方。跳跃必须在以 2 的幂 在索引中分隔的建筑物之间,而不是高度不同(这是您正在检查的)。

其次,应该根据第一次跳转的成本和剩余跳转的成本(通过递归调用获得)来制定递归。您正在寻找所有合法第一次跳跃的最低成本。如果第一次跳转到的建筑物的索引小于 N 并且距离当前起点的索引为 2 的幂,则第一次跳转是合法的。

这样的事情应该可以工作:

int calc(int arr[], int beg, int end)
{
    if (beg == end)
        return 0;
    else if (beg > end)
        throw an exception

    int minEnergy = INFINITY;
    for (int i = 1;        // start with a step of 1
         beg + i <= end;   // test if we'd go too far
         i <<= 1)          // increase step to next power of 2
    {
        int energy = abs(arr[beg + i] - arr[beg])  // energy of first jump
                   + calc(arr, beg + i, end);      // remaining jumps
        if (energy < minEnergy) {
            minEnergy = energy;
        }
    }
    return minEnergy;
}

通过目前得到的最小能量可以大大提高这个搜索的效率。那么如果abs(arr[beg + i] - arr[beg]) 不小于那个数量,就没有必要进行递归调用,因为找到的东西永远不会更小。 (事实上​​,如果abs(arr[beg + i] - arr[beg]) + abs(arr[end] - arr[beg + i]) 不小于目前最好的解决方案,你可以切断递归,因为蜘蛛侠在构建beg + i 之后至少必须花费abs(arr[end] - arr[beg + i])。)添加这个改进保留为练习。 :)

【讨论】:

  • 我们不能让for循环像for (int i = beg; i &lt;= end; i++)一样运行并检查if (beg - i) is a power of two or not, and if is, we pass in the recursive calls?
  • @JohnLui - 但是你为什么要这么做呢?我的循环简单地迭代了两个步骤的幂,并完全消除了您的方法可能产生的生成和测试成本。换句话说,(beg + i) - beg 在我的循环中总是是 2 的幂,因此无需测试它是否是。
  • 我不知道为什么但是使用这个函数给出了错误的答案。在 main 中,我只是调用这个函数并传递适当的值。
  • @JohnLui - 好吧,那段代码让我想不通。你可以尝试用一个简单的案例来调试它,看看它在哪里偏离了轨道。 :)
  • 问题是,它适用于简单的小值。但是对于较大的输入大小,由于其自​​上而下的方法,它会显示堆栈溢出。我想我将不得不使用自下而上的方法来做到这一点。任何线索都会有所帮助。 :)
猜你喜欢
  • 1970-01-01
  • 2019-07-17
  • 1970-01-01
  • 2018-07-09
  • 2016-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-24
相关资源
最近更新 更多