PAT甲级 1007 Maximum Subsequence Sum 最大连续子序列和 dp或者暴力枚举

PAT甲级 1007 Maximum Subsequence Sum 最大连续子序列和 dp或者暴力枚举_第1张图片

题意:

给一个数组序列a1,a2,…,an,求 i, j(1<=i<=j<=n),使得ai + … +aj最大,输出最大和以及ai,aj
如果有多种方案使得和最大,那么输出其中i,j最小的一组
如果所有数都小于0,那么认为最大和为0,并输出首尾元素


样例解释:

-10 1 2 3 4 -5 -23 3 7 -21
1 + 2 + 3 + 4 = 10,后面也有组3 + 7 = 10,但是由于题目说输出从左到右最先遇到的方案,因此选择前者,输出10 1 4(注意:1跟4是数值而不是下标)


Solution1: 暴力枚举(大力出奇迹

代码如下:

#include
using namespace std;

int a[10005];

int main(){
	int n;
	cin>>n;
	for(int i=0;i<n;i++){//读入a[]数组
		cin>>a[i];
	}
	int sum=-1;//记录子序列的最大和
	int temp;//中间变量
	int start;//记录开始下标
	int end1;//记录结束下标
	for(int i=0;i<n;i++){//枚举
		temp=0;
		for(int j=i;j<n;j++){
			temp+=a[j];
			if(temp>sum){//若加上a[j]结果大于sum
				sum=temp;//sum等于temp
				start=a[i];//更新起点下标
				end1=a[j];//更新终点下标
			}
		}

	}
	if(sum<0){
		cout<<0<<' '<<a[0]<<' '<<a[n-1];
	}else{
		cout<<sum<<' '<<start<<' '<<end1;
	}
	return 0;
}


Solution2: dp 复杂度 O(n)

以s[i]表示以a[i]作为结尾的最大连续子序列和是从哪个元素开始(记录下标),那么根据上面的策略,可以写出状态转移方程:

if(dp[i-1]+a[i]>a[i]){
	dp[i]=dp[i-1]+a[i];
	s[i]=s[i-1];
}else{
	dp[i]=a[i];
	s[i]=i;
}

代码如下:

#include
#include
#include
#include
#include
#include
#include
#include
#define MAX 10005
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;

int n,a[MAX],dp[MAX],s[MAX]={0};

int main(){
    scanf("%d",&n);
    bool flag=true;//判断序列中是否全是负数
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        if(a[i]>=0) flag=false;
    }
    if(flag){
        printf("0 %d %d",a[0],a[n-1]);
        return 0;
    }
    dp[0]=a[0];//边界,这个元素无法通过前面的元素得到
    for(int i=1;i<n;i++){
        if(dp[i-1]+a[i]>a[i]){
            dp[i]=dp[i-1]+a[i];
            s[i]=s[i-1];
        }else{
            dp[i]=a[i];
            s[i]=i;
        }
    }

    int k=0;
    for(int i=1;i<n;i++){//找到dp[i]最大的
        if(dp[i]>dp[k]){
            k=i;
        }
    }
    printf("%d %d %d",dp[k],a[s[k]],a[k]);
    return 0;
}

你可能感兴趣的:(PAT,暴力,从零开始的动态规划qwq)