Summary of hdoj1003+codeup2086:Max Sum Maximum Continuous Subsequence and Problem Solution

Posted by exec1 on Tue, 14 May 2019 15:40:54 +0200

Catalog

Solution method of hdoj 1003

Violent solution O (n ^ 3) / O (n ^ 2) (not recommended, probably timed out)

Divide and conquer (more complicated, just master ideas)

Ergodic summation O(n)

dp dynamic programming

The Solution Method of Codup2086

dp solution

Solution method of hdoj 1003

  • Violent solution O (n ^ 3) / O (n ^ 2) (not recommended, probably timed out)

Thought: Two-level for cycle, the first level i, the second level j, find a way to calculate the sum between I and j, and then judge the conditions to solve.

https://blog.csdn.net/ten_sory/article/details/79776473

Participate in this blog

  • Divide and conquer (more complex, just master the idea)

(excerpts from LB_Mohe Yanqi Blogs)

Assuming that the searched subarray A[low...high] is the largest subarray, using the branching strategy means that we need to divide the primitive into two subarrays of approximately the same size, then we can find the middle position mid of the array a.

Then the position of array A may be in three cases:

1. Completely located in the subarray a[low...mid]

2. Completely located in subarray a[mid + 1... high]

3. Crossing the midpoint

In the first two cases, we can use recursion directly. In the third case, we can use this strategy. Starting from the middle point, we can traverse the array left to find the maximum sum, and then traverse from the middle point to the right to find the maximum sum.

The latter two add up, i.e., get the midpoint and the largest subarray

Code (note output format)

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <algorithm>
#include <memory.h>
 
using namespace std;
const int maxn = 100000 + 10;
const int mini = -100000000;
 
int num[maxn];
//int memo[maxn][maxn];
 
int find_cross_subarray(int low,int high,int  & cross_low,int & cross_high)// low_max is the subscript that crosses the midpoint to the leftmost, and high_max is the subscript that crosses the midpoint to the rightmost.
{
	int mid = (low + high) / 2;
	int res = 0;
	
	int left_sum = mini;
	for (int i = mid; i >= low; i--)
	{
		res += num[i];
		if (res >= left_sum)		//Output the first array that meets the requirements, so try to move as close to the left as possible.
		{
			left_sum = res;
			cross_low = i;
		}
	}//for int i
 
	res = 0;
	int right_sum = mini;
	for (int i = mid + 1; i <= high; i++)
	{
		res += num[i];
		if (res > right_sum)
		{
			right_sum = res;
			cross_high = i;
		}
	}
 
	return right_sum + left_sum;
}
 
int find_max_subarray(int low, int high,int & max_low,int & max_high)	//The left and right subscripts of max_low max_high for the final answer
{
	if (high == low)
	{
		max_low = max_high = low;
		return num[high];
	}
 
	int mid = (low + high) / 2;
	int left_low, left_high, left_sum;
	int right_low, right_high, right_sum;
	int cross_low, cross_high, cross_sum;
 
	left_sum = find_max_subarray(low, mid,left_low,left_high);
	right_sum = find_max_subarray(mid + 1, high,right_low,right_high);
	cross_sum = find_cross_subarray(low, high, cross_low, cross_high);
 
	if (left_sum >= cross_sum && left_sum >= right_sum)
	{
		max_low = left_low;
		max_high = left_high;
		return left_sum;
	}
 
	if (cross_sum >= left_sum && cross_sum >= right_sum)
	{
		max_low = cross_low;
		max_high = cross_high;
		return cross_sum;
	}
 
	max_low = right_low;
	max_high = right_high;
	return right_sum;
}
 
int main()
{
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
	int casenum, length,seq = 0;
	cin >> casenum;
	while (casenum--)
	{
		if (seq != 0)
			cout << endl;
		cin >> length;
		for (int i = 0; i < length; i++)
			cin >> num[i];
		
		int max_low, max_high, res;
		res = find_max_subarray(0, length - 1, max_low, max_high);
		cout << "Case " << ++seq << ":" << endl;
		cout << res << " " << max_low + 1<< " " << max_high + 1<<endl;
	}
	return 0;
}
  • Ergodic summation O(n)

Train of thought: traversing and accumulating, sum+=a[i], updating the maximum sum value. When the sum value is less than 0, sum+a[i+1]<=a[i+1], there is no need to grow the sub-sequence again.

To restart a new subsequence

Reference code (from bloggers) echo_hello)

 #include<iostream>
using namespace std;
 
int main()
{
	int T;
	cin >> T;
	int t = 0;
	while(T--)
	{
		t ++;
		int n, i, j;
		cin >> n;
		int *a = new int[n];
		for(i=0;i<n;i++)
			cin >> a[i];
		int maxsum = -9999;
		int sum = 0;
		int startMax = 0, endMax = -1;
		int startTemp = 0, endTemp = -1;
		for(i=0;i<n;i++)
		{
			sum+=a[i];
			endTemp ++;
			if(sum>maxsum)
			{
				maxsum = sum;
				startMax = startTemp;
				endMax = endTemp;
			}
			if(sum<0)
			{
				sum = 0;
				startTemp = i+1;
				endTemp = i;
			}
		}
 
		cout << "Case " << t << ":" << endl;
		cout << maxsum << " " << startMax+1 << " " << endMax+1 << endl;
		if(T>0)
			cout << endl;
 
		delete []a;
	}
 
	return 0;
}
  • dp dynamic programming

The state transition equation dp[i]=max(dp[i-1]+a[i],a[i]), is the same as ergodic summation.

With a[i] as the objective, if the sum of the previous subsequences is not as large as itself, then the element in the new maximum subsequence is a[i]

ac code: (note to initialize the values of begin and end)

#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#define maxn 100005
using namespace std;
int a[maxn],dp[maxn];
int main()
{
    int k,ans,i,num=1,t;
    scanf("%d",&t);
    while(t--)
    {
        int begin=0,end=0;
        memset(dp,0,sizeof(dp));
        scanf("%d",&k);
        for(i=0;i<k;i++)
        {
            scanf("%d", &a[i]);
        }
        dp[0]=a[0];
        ans=dp[0];//ans is used to update the maximum sum
        for(i=1;i<k;i++)
        {
            dp[i]=max(dp[i-1]+a[i],a[i]);//State transition equation
            if(dp[i]>ans)//Updating the values of ans directly in the loop eliminates the need to sort or traverse for maximum values
            {
                ans=dp[i];
                end=i;
            }
        }
        int res=0;
        for(i=end;i>=0;i--)
        {
            res+=a[i];
            if(res==ans)
                begin=i;
        }
        printf("Case %d:\n",num++);
        printf("%d %d %d\n",ans,begin+1,end+1);
        if(t!=0)
            printf("\n");
    }
    return 0;
}

The Solution Method of Codup2086

  • dp solution

ac Code:

#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#define maxn 100000
using namespace std;
int a[maxn],dp[maxn];
int main()
{
    int k,ans,begin,end,i;
    while(scanf("%d",&k) && k!=0)
    {
        bool flag=true;
        memset(dp,0,sizeof(dp));
        for(i=0;i<k;i++)
        {
            scanf("%d", &a[i]);
            if(a[i]>0)
                flag=false;
        }
        if(flag)//All k elements are negative
        {
            printf("%d %d %d\n",0,a[0],a[k-1]);
            continue;
        }
        dp[0]=a[0];
        ans=dp[0];//ans is used to update the maximum sum
        for(i=1;i<k;i++)
        {
            dp[i]=max(dp[i-1]+a[i],a[i]);//State transition equation
            if(dp[i]>ans)
            {
                ans=dp[i];
                end=i;
            }
        }
        int res=0;
        for(i=end;i>=0;i--)
        {
            res+=a[i];
            if(res==ans)
                begin=i;
        }
        //printf("%d %d %d\n",ans,begin+1,end+1);
        printf("%d %d %d\n",ans,a[begin],a[end]);
    }
    return 0;
}

 

Topics: Programming less