最大连续子序列和多解——HDU 1003 + POJ 1050

来源:互联网 发布:淘宝网店怎么装修视频 编辑:程序博客网 时间:2024/05/20 01:37

对应HDU题目:点击打开链接

Max Sum

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 161486    Accepted Submission(s): 37830


Problem Description
Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7), the max sum in this sequence is 6 + (-1) + 5 + 4 = 14.
 

Input
The first line of the input contains an integer T(1<=T<=20) which means the number of test cases. Then T lines follow, each line starts with a number N(1<=N<=100000), then N integers followed(all the integers are between -1000 and 1000).
 

Output
For each test case, you should output two lines. The first line is "Case #:", # means the number of the test case. The second line contains three integers, the Max Sum in the sequence, the start position of the sub-sequence, the end position of the sub-sequence. If there are more than one result, output the first one. Output a blank line between two cases.
 

Sample Input
25 6 -1 5 4 -77 0 6 -1 1 -6 7 -5
 

Sample Output
Case 1:14 1 4Case 2:7 1 6
 

题意:T组数,每组一个数n,之后n个数。求n个数的最大连续子序列和与起始位置跟终点位置,如果有多个解,输出起点最小的,如有多个终点,输出终点最小的。


方法一:直接枚举。O(n^3),超时

#include <stdio.h>#include <stdlib.h>#include <string.h>#define N 100010int a[N];int main(){//freopen("in.txt", "r", stdin);int T, n, w = 0;int i, j, k;scanf("%d", &T);while(T--){scanf("%d", &n);for(i=0; i<n; i++)scanf("%d", &a[i]);int max_s = -(1<<30);int sum, left, right;for(i=0; i<n; i++){for(j=i; j<n; j++){sum = 0;for(k=i; k<=j; k++)sum += a[k];if(sum > max_s){max_s = sum;left = i;right = j;}}}printf("Case %d:\n%d %d %d\n", ++w, max_s, left + 1, right + 1);if(T) printf("\n");}return 0;}

方法二:对前i项和进行预处理,O(n^2),超时。

#include <stdio.h>#include <stdlib.h>#include <string.h>#define N 100010int a[N];int sum[N];int main(){//freopen("in.txt", "r", stdin);int T, n, w = 0;int i, j, k;scanf("%d", &T);while(T--){memset(sum, 0, sizeof(sum));scanf("%d", &n);for(i=1; i<=n; i++){scanf("%d", &a[i]);sum[i] = sum[i-1] + a[i];}int max_s = -(1<<30);int s, left, right;for(i=1; i<=n; i++){for(j=i; j<=n; j++){s = sum[j] - sum[i-1];if(s > max_s){max_s = s;left = i;right = j;}}}printf("Case %d:\n%d %d %d\n", ++w, max_s, left, right);if(T) printf("\n");}return 0;}

方法三:分治,O(nlg(n)),可AC。

#include <stdio.h>#include <stdlib.h>#include <string.h>#define N 100010int a[N];typedef struct NODE{int val, l, r;}Node;Node Max_Ans(int *A, int l, int r){Node t;if(1 == r - l){t.val = A[l];t.l = l;t.r = l;return t;}Node t1, t2, t3;int mid = l + (r - l) / 2;t1 = Max_Ans(A, l, mid);t2 = Max_Ans(A, mid, r);if(t1.val >= t2.val) t = t1;else t = t2;int i, v, L, R;v = 0; L = A[mid -1]; t3.l = mid - 1;for(i=mid-1; i>=l; i--){v += A[i];if(v >= L){L = v;t3.l = i;}}v = 0; R = A[mid]; t3.r = mid;for(i=mid; i<r; i++){v += A[i];if(v > R){R = v;t3.r = i;}}t3.val = L + R;if(t3.val >= t.val)t = t3;return t;}int main(){//freopen("in.txt", "r", stdin);int T, w = 0;int n;Node max_s;int i, k;scanf("%d", &T);while(T--){scanf("%d", &n);for(i=0; i<n; i++){scanf("%d", &a[i]);}max_s = Max_Ans(a, 0, n);printf("Case %d:\n%d %d %d\n", ++w, max_s.val, max_s.l + 1, max_s.r + 1);if(T) printf("\n");}return 0;}

方法四:线段树,可AC。

#include <stdio.h>#include <stdlib.h>#include <string.h>#define ms(x,y) memset(x,y,sizeof(x))  #define MAX(x,y) ((x)>(y)?(x):(y))  #define LL long long  const int MAXN=100000+10;  const int INF=1<<30;  using namespace std;  int sum[MAXN<<2];  int msum[MAXN<<2];  int lsum[MAXN<<2];  int rsum[MAXN<<2];  int ll[MAXN<<2];  int lr[MAXN<<2];  int ml[MAXN<<2];  int mr[MAXN<<2];  int rl[MAXN<<2];  int rr[MAXN<<2];    void up(int root)  {      int lroot = root<<1;      int rroot = root<<1|1;      sum[root] = sum[lroot] + sum[rroot];      lsum[root] = lsum[lroot];      rsum[root] = rsum[rroot];      //维护前缀      ll[root] = ll[lroot];      lr[root] = lr[lroot];      int sl = sum[lroot] + lsum[rroot];      if(sl > lsum[root]){          lsum[root] = sl;          lr[root] = lr[rroot];      }      //维护后缀      rl[root] = rl[rroot];      rr[root] = rr[rroot];      int sr = sum[rroot] + rsum[lroot];      if(sr >= rsum[root]){          rsum[root] = sr;          rl[root] = rl[lroot];      }      //维护区间最值      ml[root] = ml[lroot];       mr[root] = mr[lroot];       msum[root] = msum[lroot];      if(msum[root] < rsum[lroot] + lsum[rroot]){          msum[root] = rsum[lroot] + lsum[rroot];          ml[root] = rl[lroot];          mr[root] = lr[rroot];      }      if(msum[root] < msum[rroot]){          msum[root] = msum[rroot];          ml[root] = ml[rroot];          mr[root] = mr[rroot];      }  }    void Build(int root, int left, int right)  {      if(left == right){          scanf("%d", &sum[root]);          lsum[root] = sum[root]; ll[root] = left; lr[root] = right;          msum[root] = sum[root]; ml[root] = left; mr[root] = right;          rsum[root] = sum[root]; rl[root] = left; rr[root] = right;          return;      }      int mid = (left + right)>>1;      Build(root<<1, left, mid);      Build(root<<1|1, mid+1, right);      up(root);     }    struct Node  {      int msum, lsum, rsum, sum;      int ll, lr, ml, mr, rl, rr;  };    Node query(int root, int left, int right, int l, int r)  {      if(l == left && right == r){          Node N;          N.sum = sum[root];          N.msum = msum[root];          N.lsum = lsum[root];          N.rsum = rsum[root];          N.ll = ll[root];          N.lr = lr[root];          N.ml = ml[root];          N.mr = mr[root];          N.rl = rl[root];          N.rr = rr[root];          return N;      }      int mid = (left + right)>>1;      Node res,res1,res2;      int lroot = root<<1;      int rroot = root<<1|1;      int markl = 0, markr = 0;      if(r <= mid) return res = query(lroot, left, mid, l, r);      if(l > mid) return res2 = query(rroot, mid+1, right, l, r);      else{          res = query(lroot, left, mid, l, mid);          res2 = query(rroot, mid+1, right, mid+1, r);            res1.sum = res.sum + res2.sum;          res1.lsum = res.lsum;          res1.rsum = res2.rsum;          res1.ll = res.ll;          res1.lr = res.lr;          LL sl = res.sum + res2.lsum;          if(sl > res1.lsum){              res1.lsum = sl;              res1.lr = res2.lr;          }          res1.rl = res2.rl;          res1.rr = res2.rr;          LL sr = res2.sum + res.rsum;          if(sr >= res1.rsum){              res1.rsum = sr;              res1.rl = res.rl;          }          res1.msum = res.msum;          res1.ml = res.ml;          res1.mr = res.mr;          if(res1.msum < res.rsum + res2.lsum){              res1.msum = res.rsum + res2.lsum;              res1.ml = res.rl;              res1.mr = res2.lr;          }          if(res1.msum < res2.msum){              res1.msum = res2.msum;              res1.ml = res2.ml;              res1.mr = res2.mr;          }          return res1;      }  }  int main(){    //freopen("in.txt", "r", stdin);    int T, n, w = 0;    int i, j, k;    Node max_s;    scanf("%d", &T);    while(T--)    {        scanf("%d", &n);        Build(1, 1, n);        max_s = query(1, 1, n, 1, n);        printf("Case %d:\n%d %d %d\n", ++w, max_s.msum, max_s.ml, max_s.mr);        if(T) printf("\n");    }    return 0;}

方法五:扫一遍,累加sum, 当sum < 0 时,置sum 为0。如:

-1  5  7  -9  2   -7  -2  1  3  可分成

-1 | 5  12   3  5 | -7 | -2 | 1  4

竖线为分界。比较每个区间,取最大值。

其实还可看做是DP:sum[i] = max{sum[i-1] + a[i],   a[i]};   sum[i]表示以a[i]结尾的最大连续和,最后再在sum[]里面找最大值就行了。

思路来自:http://blog.csdn.net/hcbbt/article/details/10454947

#include <stdio.h>#include <stdlib.h>#include <string.h>int main(){//freopen("in.txt", "r", stdin);int T, w = 0;int n, num;int beg, end, max_s, tmp;int i, k;scanf("%d", &T);while(T--){scanf("%d", &n);max_s = -(1<<30);tmp = 0;beg = end = k = 1;for(i=1; i<=n; i++){scanf("%d", &num);tmp += num;if(tmp > max_s){max_s = tmp;beg = k;end = i;}if(tmp < 0){tmp = 0;k = i + 1;}}printf("Case %d:\n%d %d %d\n", ++w, max_s, beg, end);if(T) printf("\n");}return 0;}

二维最大连续子序列和:

To the Max
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 42224 Accepted: 22464

Description

Given a two-dimensional array of positive and negative integers, a sub-rectangle is any contiguous sub-array of size 1*1 or greater located within the whole array. The sum of a rectangle is the sum of all the elements in that rectangle. In this problem the sub-rectangle with the largest sum is referred to as the maximal sub-rectangle. 
As an example, the maximal sub-rectangle of the array: 

0 -2 -7 0 
9 2 -6 2 
-4 1 -4 1 
-1 8 0 -2 
is in the lower left corner: 

9 2 
-4 1 
-1 8 
and has a sum of 15. 

Input

The input consists of an N * N array of integers. The input begins with a single positive integer N on a line by itself, indicating the size of the square two-dimensional array. This is followed by N^2 integers separated by whitespace (spaces and newlines). These are the N^2 integers of the array, presented in row-major order. That is, all numbers in the first row, left to right, then all numbers in the second row, left to right, etc. N may be as large as 100. The numbers in the array will be in the range [-127,127].

Output

Output the sum of the maximal sub-rectangle.

Sample Input

40 -2 -7 0 9 2 -6 2-4 1 -4  1 -18  0 -2

Sample Output

15

题意:给出一个矩阵,求和最大的子矩阵,输出和。

思路:对某两行,列于列相加,组成新的数组,求最大连续和。


#include <stdio.h>#include <stdlib.h>#include <string.h>#define N 105int a[N][N];int sum[N];int main(){//freopen("in.txt", "r", stdin);int n;while(~scanf("%d", &n)){int i, j, k, p;for(i=0; i<n; i++){for(j=0; j<n; j++){scanf("%d", &a[i][j]);}}int max_s = -(1<<30), tmp;for(i=0; i<n; i++){memset(sum, 0, sizeof(sum));for(j=i; j<n; j++){tmp = 0;for(k=0; k<n; k++){//for(p=i; p<=j; p++)//tmp += a[p][k];sum[k] += a[j][k];tmp += sum[k];if(tmp > max_s) max_s = tmp;if(tmp < 0) tmp = 0;}}}printf("%d\n", max_s);}return 0;}









0 0
原创粉丝点击