目录

hdoj 1003求解方法

暴力求解O(n^3)/O(n^2)(不推荐,很可能会超时)

分治法(比较复杂,掌握思想即可)

遍历求和法O(n)

dp动态规划(强推)

codeup2086的求解方法

dp求解


hdoj 1003求解方法

  • 暴力求解O(n^3)/O(n^2)(不推荐,很可能会超时)


思路 :两层for循环,第一层i,第二层j,想办法计算i~j之间的和,再判断条件求解

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

具体可参加此博客

  • 分治法(比较复杂,掌握思想即可)


(摘自 LB_莫贺延碛的博客)

假设寻找的子数组A[low...high]为最大子数组,使用分支策略,意味着我们需要将原数组分为两个规模近似相同的子数组,那么我们可以找到数组a的中间位置mid

则数组A的位置可能有三种情况:

1.完全位于子数组a[low...mid] 中

2.完全位于子数组a[mid + 1... high]中

3.跨过中点

其中前两种情况我们直接使用递归即可,至于第三种情况,可以用这种策略,从中点开始,向左遍历数组求出最大的和 ,然后在从中点向右遍历,求出最大的和

之后两者相加,即获得过中点 和最大的子数组

代码(注意输出格式)

#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 为过中点 到达最左边的下标,high_max 为过中点 到达最右边的下标
{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)      //输出第一个 满足要求的数组 所以要尽量向左边靠拢{left_sum = res;cross_low = i;}}//for int ires = 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)  //max_low max_high为最终答案的左右下标
{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;
}
  • 遍历求和法O(n)


思路:边遍历边累加,sum+=a[i],更新最大的sum值,当sum的值小于0 ,sum+a[i+1]<=a[i+1],则没有必要再曾长该子序列

则重新开始新的子序列

参考代码(来自博主 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动态规划(强推)


状态转移方程dp[i]=max(dp[i-1]+a[i],a[i]),和遍历求和思想相同

以a[i]为目标,判断它加上前面的子序列的和还没有自己本身大的话,那么新的最大子连续序列中的元素即a[i]

ac代码:(注意要初始化begin和end的值)

刚学dp的时候参考的网上的代码:

#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用于更新最大的和for(i=1;i<k;i++){dp[i]=max(dp[i-1]+a[i],a[i]);//状态转移方程if(dp[i]>ans)//直接在循环内更新ans的值,就不用再sort或者遍历寻找最大值了{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;
}

学了一段时间算法之后自己写的代码:

用f[]记录max sum子序列的起始位置

#include <bits/stdc++.h>
#define maxn 1000005
#define inf 2147483648
using namespace std;
typedef long long ll;
int f[maxn],dp[maxn],a[maxn];
int main()
{//freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);int t,num=1,n;scanf("%d",&t);while(t--){memset(dp,0,sizeof(dp));if(num!=1) printf("\n");printf("Case %d:\n",num++);ll sum=0;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);f[1]=1;dp[1]=a[1];int msum=a[1],k=1;for(int i=2;i<=n;i++){if(dp[i-1]+a[i]>=a[i]){f[i]=f[i-1];dp[i]=dp[i-1]+a[i];}else{f[i]=i;dp[i]=a[i];}//cout<<dp[i]<<endl;if(dp[i]>msum){k = i;msum=dp[i];}}printf("%d %d %d\n",msum,f[k],k);}return 0;
}

codeup2086的求解方法

  • dp求解


ac代码:

和hdoj1003同样的方法,也可以用f[]记录子序列起始的位置,只需对下面的代码做一点修改即可,就不再单独贴代码了。

#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)//k个元素全为负数{printf("%d %d %d\n",0,a[0],a[k-1]);continue;}dp[0]=a[0];ans=dp[0];//ans用于更新最大的和for(i=1;i<k;i++){dp[i]=max(dp[i-1]+a[i],a[i]);//状态转移方程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;
}

hdoj1003+codeup2086:Max Sum最大连续子序列和(dp基础题+dp入门-----分治/遍历求和/dp)相关推荐

  1. SDNU 1330.Max Sum(最大子序列和)

    Description 给定长度为n的正整数序列a1,a2,-,an. 令sum=ab1+ab2+-+abm,并且满足:ab1<ab2<-<abm:b1<b2<-< ...

  2. 动态规划经典题目:最大连续子序列和、最大不连续子序列和

    1.最大连续子序列和:  记数组为nums 思路: 记录dp[i]为i位置结尾的最大连续子序列和 则有dp[i]=dp[i-1]>0?(dp[i-1]+nums[i]):nums[i]; 然后求 ...

  3. Maximum Sum UVA - 108(连续子序列最大和—变形之子矩阵最大和)

    题目大意:给出 n*n 的矩阵,找每隔数字之和最大的子矩阵,输出最大和.  解题思路:枚举矩阵左上和右下的坐标,分别合并子矩阵的每列,使得二维转化为一维,然后利用连续子序列最大和去做就行. Time ...

  4. 1007. Maximum Subsequence Sum (25)-PAT甲级真题(最大连续子序列和、动态规划dp)

    Given a sequence of K integers { N1, N2, -, NK }. A continuous subsequence is defined to be { Ni, Ni ...

  5. 最大连续子序列和-动态规划

    题目描述: 给定K个整数的序列{ N1, N2, -, NK },其任意连续子序列可表示为{ Ni, Ni+1, -, Nj },其中 1 <= i <= j <= K.最大连续子序 ...

  6. 《github一天一道算法题》:分治法求数组最大连续子序列和

    看书.思考.写代码. /**************************************** copyright@hustyangju * blog: http://blog.csdn.n ...

  7. 求最大连续子序列和——解法1 – 暴力出奇迹||解法2 – 分治

    解法1 – 暴力出奇迹 穷举出所有可能的连续子序列,并计算出它们的和,最后取它们中的最大值 空间复杂度:O(1),时间复杂度:O (n 3) class Solution {public int ma ...

  8. HDU_1003 Max Sum

    点击打开链接 Max Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) T ...

  9. hdu 5586(最大连续子序列和)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5586 官方题解: 令A i =f(A i )−A i  ,然后求一遍最大连续子序列和就能知道最多能增加 ...

  10. 2020春招机考汇总1(Python):农场养鸡、连续子序列最大值的期望

    第一题:农场养鸡 n个农场,第i个农场有a[i]只鸡,每天每个农场都会增加k只鸡.每晚农场主都会选择鸡最多的农场,将该农场鸡的个数除以2下取整,在m天后剩下多少只鸡? 输入: 第一行输入三个int类型 ...

最新文章

  1. JSon数据查询---Jlinq
  2. java 1099_【LeetCode(Java) - 1099】小于 K 的两数之和
  3. python【力扣LeetCode算法题库】16- 最接近的三数之和
  4. 【AOP 面向切面编程】Android Studio 使用 AspectJ 监控方法运行 ( 定义连接点注解 | 定义 Aspect 切面 | 定义切入点 | 逐个处理切入点的各个连接点 )
  5. 数据结构学习笔记(六):二叉树(Binary Tree)
  6. CodeSmith实体类模板
  7. 你准备好了吗,江湖来了
  8. 编译错误: Too much data space used by DLL's in MODULES section
  9. Elasticsearch 7.x 最详细安装及配置
  10. dsp 链接命令文件的写法
  11. 计算机专业搜题软件免费,QuestionHelper(pc搜题工具)
  12. 巴塞尔协议中的计算公式_巴塞尔协议演变及计算方法简单解析
  13. Pivotal任命Lionel Lim为Pivotal公司副总裁兼亚太区常务董事
  14. Codeforces Round #815 (Div. 2) A-D2
  15. 优信php面试流程_php面试的的时候你被提过哪些问题?
  16. 手机植入木马可以监视你的一举一动,黑客是怎样入侵别人手机的?
  17. 商业智能中的决策, 数据和数据处理方法
  18. 如何评价 Richard Stallman?
  19. 【愚公系列】2023年01月 Java教学课程 009-类型转换
  20. lq到底是什么意思_马云说的IQ、EQ、​LQ什么意思,懂了这些才是关键

热门文章

  1. 广东中学计算机课可教什么,广东实验中学课程设置如何?有什么特色?
  2. Java基础Arrays类
  3. python3 3种方式分别用for循环、while循环计算1到100的和
  4. mybatis中的三种多表查询的方式详解,业务装配,N+1,多表查询的sql
  5. c语言开发视频监控系统,基于Crotex_A8平台的本地视频监控系统.doc
  6. 计算机电源在线工作,计算机开关电源的工作原理与维修2.pdf
  7. mybatis中Mapper映射
  8. mongodb之使用explain和hint性能分析和优化
  9. Debian Gnu/Linux8.5安装GOLANG环境笔记
  10. 转载:《TypeScript 中文入门教程》 17、注解