繁体   English   中英

c编程拼图

[英]c programming puzzle

给定一个数组,其所有元素都是正数,找到一个子序列的最大总和,其约束条件是序列中没有2个数字应该在数组中相邻。 所以3 2 7 10应该返回13(3和10的总和)或3 2 5 10 7应该返回15(3,5和7的总和)。

我尝试使用所有可能允许的总和,然后找到最大值(蛮力方法)但是有更好的方法。 例如[3 2 7 10]我总和3,7和2,10并取最大值。


更多例子:

  • [3,2,7,1]:返回10
  • [6,2,1,4]:返回10
  • [8,9,5,1]:返回13
  • [29,77,16]:返回77
  • [29,44,16]:返回45

这个问题可以通过动态编程来解决。

假设我们有一个整数数组:

i[1], i[2], i[3], ..., i[n], i[n+1], i[n+2]

我们将数组分为两部分:第一部分包含前n个整数,第二部分是最后两个整数:

{i[1], i[2], i[3], ..., i[n]}, {i[n+1], i[n+2]}

我们将M_SUM(n)表示为每个要求的前n个整数的最大和。

将有两种情况:

  1. 如果i[n]不计入M_SUM(n) ,那么M_SUM(n+2) = M_SUM(n) + MAX(i[n+1], i[n+2])
  2. 如果i[n]被计入M_SUM(n) ,那么M_SUM(n+2) = M_SUM(n) + i[n+2]

那么,我们正在寻找的值M_SUM(n+2)将是上述两个值中较大的值。

然后我们可以有一个非常天真的伪代码如下:

function M_SUM(n)
   return MAX(M_SUM(n, true), M_SUM(n, false))

function M_SUM(n, flag)
   if n == 0 then return 0
   else if n == 1
      return flag ? i[0] : 0
   } else {
      if flag then
         return MAX(
                M_SUM(n-2, true) + i[n-1], 
                M_SUM(n-2, false) + MAX(i[n-1],i[n-2]))
      else
         return MAX(M_SUM(n-2, false) + i[n-2], M_SUM(n-2, true))
   }

“flag”表示“允许使用最后一个整数”

该算法具有指数时间复杂度。

可以采用动态编程技术来消除M_SUM的不必要的重新计算。

将每个M_SUM(n, flag)存储到* 2矩阵中。 在递归部分中,如果矩阵中不存在这样的值,则计算它。 否则,只需从矩阵中获取值。 这会将时间复杂度降低为线性。

该算法将具有O(n)时间复杂度和O(n)空间复杂度。

Python,六行使用动态编程( 不是真的!见下面的编辑。 ):

def run(x):
    if len(x) == 0:
        return 0
    elif len(x) <= 2:
        return max(x)
    return max(x[0] + run(x[2:]), x[1] + run(x[3:]))

编辑和回滚:虽然上面的解决方案生成了正确的答案,但它不是动态编程。 下面是一个,它使用较少的函数调用:

def main(x):
    return max(helper(x))

def helper(x):
    if len(x) == 1:
        return (0, x[0])
    a, b = helper(x[:-1])
    return (max(a, b), x[-1] + a)

以[3,2,5,10,7]为例

解决方案使用动态编程

维护两个数组,如最后两行所示

alt text http://img44.imageshack.us/img44/4843/newgp.jpg

答案将是最后一列中最多两个值(红色粗体)

F#解决方案:

let rec maxsubset = function
    | [] -> 0
    | x::[] -> x
    | x::y::xs -> max (maxsubset (y::xs)) (x + maxsubset xs)

轻松适应类C语言:

using System;
using System.Linq;

namespace Juliet
{
    class Program
    {
        static int MaxSubset(int[] arr, int offset)
        {
            if (offset >= arr.Length)
                return 0;
            else
                return Math.Max(MaxSubset(arr, offset + 1), arr[offset] + MaxSubset(arr, offset + 2));
        }

        static void Test(params int[] nums)
        {
            Console.WriteLine("----------------");
            Console.WriteLine("MaxSubset({0}) = {1}", String.Join(", ", nums), MaxSubset(nums, 0));
        }

        static void Main(string[] args)
        {
            Test(3, 2, 7, 1);
            Test(6, 2, 1, 4);
            Test(8, 9, 5, 1);
            Test(29, 77, 16);
            Test(29, 44, 16);
            Test(239, 2, 3, 111, 1, 4, 546, 4, 3);
            Test(100, 1, 1, 100);
            Console.ReadLine();
        }
    }
}

package com.dan.alg.recursion;

/ ** *问题:给定一个正数组,找到一个子序列*的最大总和,其约束条件是序列中没有2个数字应该在数组中相邻。 *所以3 2 7 10应该返回13(3和10的总和)或3 2 5 10 7应该返回15 *(3,5和7的总和)。以最有效的方式回答问题。 *

*解决方案:我们将向后递归构建解决方案(从数组的最后一个位置*开始并按照我们的方式开始),基于以下观察:*

*位置p的最大总和可以从以下两个值的最大值中获得:* V1 =位置p的值+位置p-2的最大总和(记住,两个元素不能相邻)* V2 =位置的最大总和p - 1 * * @author dan * /

公共课MaxSumNoNeighbours {

private static int [] arr = { 29, 44, 16 };

/**
 * Determine the max sum for the current position.
 * 
 * @param currentPos    the current position in the array.
 */
private static int maxSum(final int currentPos) {
    //  The sum is zero if we are outside of the bounds.
    if (currentPos < 0) {
        return 0;
    }

    return Math.max(
            arr[currentPos] + maxSum(currentPos - 2), 
            maxSum(currentPos - 1));
}

public static void main (final String [] args) {
    //  Start from the end of the array and work your way forwards
    System.out.println(maxSum(arr.length - 1));
}

}

sum[0] = 0;
sum[1] = 0;

for(i = 0; i < arraylength; i++) 
    sum[i & 1] += array[i];

printf("sum = %u\n", MAX(sum[0], sum[1]));
printf("homework completed\n");

可爱的问题。 最简单的方法似乎是迭代地考虑数组,保持两个最佳 - 最远的总和:允许使用[i]时可以得到的最佳总和,以及使用[i]时可以获得的最佳总和是允许的。 在python中:

def best(arr):
    # best sums of zero length array are 0
    ok, bad = 0,0 

    for x in arr:
        # best sum if we can use x is to use it,
        # because all elements are positive
        ok += x

        # moving along one step means we can't
        # use the ok sum, and can use the bad sum
        bad, ok = ok, bad

        # but just because we could use ok, doesn't
        # mean we have to, so if it's better, use
        # that path
        if bad < ok:
            bad = ok

    # bad is then our best possible sum
    return bad
{

int a[10]={1,2,3,4,5,6,7,89,8,9};

int k=0,i,j,l;
int sum[36],max;

for (i=0;i<10;i++)
{
for (j=i+2;j<10;j++,k++)
sum[k]=a[i]+a[j];
}
max=a[0];
for(i=0;i<36;i++)
printf("sum[%d] is %d\n",i,sum[i]);

for(l=1;l<36;l++)
{
if(max>sum[l])
continue;
else
max=sum[l];
}
printf("%d is the max sum",max);
}
int findSum(int* arr, int sz)
{
    if( sz <= 0) return 0;

    if( sz == 1)
    {
        return arr[0];
    }
    else
    {
        int a = arr[0] + findSum(arr+2, sz-2); 

        int b = findSum(arr+1, sz-1);

        if( a >= b)
            return a;
        else 
            return b;
    }
}

考虑中间元素,它可能是解决方案的一部分。 对于每种情况,找到左右剩余子列表的最佳解决方案并将它们组合起来,然后选择两种情况中较好的一种。

int choose( int n)
{
   if((n==1) || (n==0))
       return array[n];
   if( n==2)
       return array[0];

   totalSum += max(choose(n-2), choose(n-3));
}

max是一个从最大值中获取最大值的函数。

对于ARRAY“数组”,对数组的每个元素进行函数调用,并将最大结果存储在另一个数组中(比如arrayOfMax [n])

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM