【问题标题】:Selection of maximum sub-array from the array从数组中选择最大子数组
【发布时间】:2016-07-28 05:01:54
【问题描述】:

给定一个长度为n 的数组,如果不允许选择数组的两个以上连续元素,则需要找到一个可以选择的最大元素总和。例如;

n=5;
arr[5] = {10,3,5,7,3};
Output : 23
10+3+7+3=23

所以我写了这段代码;

#include <stdio.h>
#include <stdlib.h>
int max=0;
void solve(int arr[],int ind,int sum,int n,int count)
{
    if(ind==n){
          if(sum>max)
              max=sum;
      }
      else{
          sum+=arr[ind];
          if(ind==n-1)
            solve(arr,ind+1,sum,n,1);
          if(ind==n-2 && count>1)
            solve(arr,ind+2,sum,n,1);
          if(ind<n-1 && count<2){
              count++;
              solve(arr,ind+1,sum,n,count);
          }
          if(ind<n-2)
              solve(arr,ind+2,sum,n,1);
          if(ind<n-3)
              solve(arr,ind+3,sum,n,1);
      }
}
int main()
{
    int n;
    scanf("%d",&n);
    int i=0,arr[n];
    while(i<n){
        scanf("%d",&arr[i]);
        i++;
    }
    int count=1;
    //going into all three possibilities
    solve(arr,0,0,n,count);
    solve(arr,1,0,n,count);
    solve(arr,2,0,n,count);
    printf("%d\n",max);
    return 0;
}

此程序会为 n&lt;1000 生成预期的输出,但会显示较大输入的运行时错误 (SIGSEGV)。可能是什么原因? 也欢迎更有效的解决方案.....

【问题讨论】:

  • 可能是递归太深导致堆栈溢出?但是数量可能太少而不会引起呢?
  • 请先尝试使用调试器确定 SIGSEGV 的原因。
  • 给定n&lt;200000arr[i]&lt;10000....会不会造成溢出..
  • 对于每个级别的递归,堆栈上大约有 30 个字节的信息。所以n=33000 将在堆栈上放置大约 1 兆字节。这可能足以溢出堆栈。
  • @user3386109 你能建议另一种解决这个问题的方法吗...

标签: c arrays algorithm recursion runtime-error


【解决方案1】:

使用动态规划

DP[i]:“i”索引中的最大值

有7种情况:

1- 使用第一个和第二个元素

2- 使用第二个和第三个元素

3- 使用第一个和第三个元素

4- 只使用第一个元素

5- 只使用第二个元素

6- 只使用第三个元素

7- 不使用任何元素

int F(int[] a)
    {
        if (a.Length == 1)
        {
            return Max(a[0], 0);
        }
        int n = a.Length;
        int[] DP = new int[n];
        DP[n - 1] = Max(a[n - 1], 0);
        DP[n - 2] = DP[n - 1] + Max(a[n - 2], 0);
        for (int i = n - 3; i >= 0; i--)
        {
            DP[i] = Max(a[i], 0) + Max(a[i + 1], 0) + (i + 3 < n ? DP[i + 3] : 0);// first and second
            DP[i] = Max(DP[i], Max(a[i + 1], 0) + Max(a[i + 2], 0) + (i + 4 < n ? DP[i + 4] : 0));// second and third
            DP[i] = Max(DP[i], Max(a[i + 0], 0) + Max(a[i + 2], 0) + (i + 4 < n ? DP[i + 4] : 0));// first and third
            DP[i] = Max(DP[i], Max(a[i + 0], 0) + (i + 2 < n ? DP[i + 2] : 0));// first
            DP[i] = Max(DP[i], Max(a[i + 1], 0) + (i + 3 < n ? DP[i + 3] : 0));// second
            DP[i] = Max(DP[i], Max(a[i + 2], 0) + (i + 4 < n ? DP[i + 4] : 0));// third
            DP[i] = Max(DP[i], DP[i + 1]);// none
        }
        return DP[0];
    }

例子1:

int[] a = new int[] { 10, 3, 5, 7, 3 };
writer.WriteLine(F(a));

输出:

23

例子2:

int[] a = new int[] { 1, 5, 2, 6, 9, 8, 20, 12, 41, 3, 0, 9, 95, 6, 74, 85, 20, 14, 26, 35, 14, 72, 15 };
writer.WriteLine(F(a));

输出:

496

Implementation in C

【讨论】:

  • OP 使用 C 而不是 C++
  • @mojtaba357 你能把上面的代码转换成Michi提到的c吗……不过我能理解基本的想法……如果在c中对我更有帮助。 ...谢谢..
  • @yobro97 添加到末尾。检查一下。
  • OP 正在寻找可扩展到长度为 n 的数组的解决方案,而您的代码仅适用于他提供的 n=5 的示例。您将如何更改您的代码以扩展到任意大小的数组?
  • +1 用于 DP 解决方案,这是我的疏忽.. 现在我正在仔细查看代码,肯定会大吃一惊。
【解决方案2】:

这个问题有一个相当简单的动态规划解决方案。

数组中的每一项都代表一个二元选择:可以选择也可以不选择。但是如果连续选择了两个项目,则不能选择下一个项目。所以对于数组中的每个项目,我们需要跟踪三个和

  • 当前项目未被选中时的最佳总和
  • 当前项目被选中,而前一个项目被选中时的最佳总和
  • 当前项目被选中,前一个项目被选中时的最佳总和

代码如下:

#include <stdio.h>

#define max3(a) (a[0]>a[1] ? a[0]>a[2]?a[0]:a[2] : a[1]>a[2]?a[1]:a[2])

int main( void )
{
    int array[] = { 10,3,7,55,60,62,4,2,5,42,8,9,12,5,1 };
    int N = sizeof(array) / sizeof(array[0]);
    int dp[N][3];

    dp[0][0] = 0;
    dp[0][1] = array[0];
    dp[0][2] = 0;
    for ( int i = 1; i < N; i++ )
    {
        dp[i][0] = max3(dp[i-1]);
        dp[i][1] = dp[i-1][0] + array[i];
        dp[i][2] = dp[i-1][1] + array[i];
    }
    printf( "%d\n", max3(dp[N-1]) );
}

这个程序的输出是208。要了解它是如何计算的,请查看 dp 数组的内容:

请注意,直到最后才知道通过 dp 数组的正确路径。在此示例中,两个端点具有相同的和,因此通过数组的两条路径给出相同的答案。这两条路径代表了这些选择:

array:  10  3  7 55 60 62  4  2  5 42 8  9 12 5  1 
red:    10    +7   +60+62    +2   +42+8   +12+5     = 208  
blue:   10    +7   +60+62       +5+42   +9+12   +1  = 208

【讨论】:

    猜你喜欢
    • 2015-03-06
    • 1970-01-01
    • 2021-11-09
    • 2020-12-07
    • 2013-08-22
    • 1970-01-01
    • 2014-03-12
    • 2019-07-31
    • 2015-05-28
    相关资源
    最近更新 更多