最大字段问题-含最大子矩阵和m子段和

合集下载

最大子数组和问题

最大子数组和问题

最大子数组和问题所谓最大子数组问题,就是在给定的一串包含正数,负数的数组中,找出最大的子数组的和例如:输入:1,-2,3,10,-4,7,2,-5最大子数组和为18一般而言,有三种办法可以用于解决这个问题1.暴力破解法暴力破解法就是将所有的子数组的和全部加起来,取最大的。

2.分治法分治法的核心思想就是将大问题分解为小问题,再将小问题逐个解决,然后从小问题的解得到原问题的解如果把数组从任一点(一般取中点)分为两个数组,那最大子数组只能存在于三个位置1.左数组2.右数组3.左数组最大后缀和右数组最大前缀的拼接(我称为中间数组)然后把分得的两个数组使用递归算法继续分割,直到每个子数组只含有一个元素此时两两进行判断:若左数组较大,并返回左数组的值,右数组一样若中间数组较大(此处即左右最大前缀和后缀的和,则返回这个和)3.动态规划法定义数组p,p[i]表示从arr[0]开始的前i项和,定义p[-1]=0,设arr=[1,-3,5,-2,4]则有:p[0]=max(p[-1]+arr[0],arr[0]) p[0]=max(0+1,1)=1;p[1]=max(p[ 0]+arr[1],arr[1]) p[1]=max(1-3,-3)=-2;p[2]=max(p[ 1]+arr[2],arr[2]) p[2]=max(-2+5,5)=5;p[3]=max(p[ 2]+arr[3],arr[3]) p[3]=max(5-2,-2)=3;p[4]=max(p[ 3]+arr[4],arr[4]) p[4]=max(3+4,4)=7;所以该数组的最大子数组之和为7不难发现p[i]的值是否改变的判断依据是p[i-1]+arr[i]是否大于arr[i]即p[i-1]+arr[i]>arr[i]?p[i]=p[i-1]+arr[i]:p[i]=arr[i];进一步思考,能否只用一个变量来起到代替数组p的作用呢?答案是肯定的经过观察,我们发现取到arr[i]这个值的前提是,arr[i]需要给我们的最大子数组之和的这个和带来正面作用,也就是让子数组之和更大,这样的话我们才会取到这个arr[i]所以,我们可以用一个变量thisMax表示当前累加的和,如果它加上arr[i]之后比原来的max更大(也就是对max起正面作用),那我们就把这一项算入到最大子数组当中,另外,如果thisMax+arr[i]之后导致arr[i]比原先还要小,我们就可以理解为thisMax在求最大子数组之和这件事上没有发挥正面作用,所以我们以arr[i]为第一项重新开始累计最大子数组之和.这样,只需要一个循环我们就可以解决问题。

0030算法笔记——最大团问题和图的m着色问题

0030算法笔记——最大团问题和图的m着色问题
// 计算最大团 void Clique::Backtrack(int i) { 3if (i > n) // 到达叶结点 3{ 33for (int j = 1; j <= n; j++) 33{ 333bestx[j] = x[j]; 333cout<<x[j]<<" "; 33} 33cout<<endl; 33bestn = cn; 33return; 3} 3// 检查顶点 i 与当前团的连接 int OK = 1; 3for (int j = 1; j < i; j++) 3if (x[j] && a[i][j] == 0) 3{ 33// i与j不相连 33OK = 0; 33break; 3}
3if (OK)// 进入左子树 3{ 33x[i] = 1; 33cn++; 33Backtrack(i+1); 33x[i] = 0; 33cn--; 3}
if (cn + n - i >= bestn)// 进入右子树 3{ 33x[i] = 0; 33Backtrack(i+1); 3} }
3333 如果U∈V且对任意u,v∈U有(u, v)不属于E,则称U是G的空子图。G的空子图U是G的独立集当且仅当U不包 含在G的更大的空子图中。G的最大独立集是G中所含顶点数最多的独立集。
3333 对于任一无向图G=(V, E),其补图G'=(V', E')定义为:V'=V,且(u, v)∈E'当且仅当(u, v)∈E。 3333 如果U是G的完全子图,则它也是G'的空子图,反之亦然。因此,G的团与G'的独立集之间存在一一对应的 关系。特殊地,U是G的最大团当且仅当U是G'的最大独立集。

最大子长方体问题的动态规划算法

最大子长方体问题的动态规划算法
计算
。 一。
(l i, √ ,l k ) i, j 2 k , 。 2 l 2
O 气皿 l { l 《, —l
0 《 I 杜 p—I
3 2 问题分 析 .
m x s i, , √ ,l k )= a (l i j 2 k , 2l 2
Z a g Yu n h n wa W a g X a g a n i n h i・
( 0 e f o p t n frai e nl y L 0 i om l n e i , a a i n g 16 2 ,hn ) c f m u r dl o t HTc o g ,i n gN r a U ir t D l nL oi 10 9 C i f oC ea n m 0 h o a n vs y i a n a
3 问题的符号化表示及分 析
3 1 问题 的符 号化 .
用三维数组 。 O m一1 [ : [: ] O n—1 [ : ] O P一1 表示 给定的整 ] 数长方体 , 中: n和 P分别表示 原长方体 的长 、 其 m、 宽和 高 , 数组 a中保存的是各小立 方体 中所 含的数字 ; 子数 组 a i: ] [l i [ 2 ] 1 ] 示以 (lj ,1 和 (2 ,2 为体 对角 线两 个端 [ : 表 i, k ) i, k ) l 点的子长方形 , 问题 为确定一个子长方体的 i 、 l7、l 则 l ij 、 k 和 2 2 坦, 使得其所包含的各子立方体 中的整数之和达到最大 。若令 ;
ag rtm s a ay e n ic s e . i lt n rs l h w i i e fcie loi h i n ls d a d d s u s d Smu a i e ut s o t s f t . o s e v Ke wo d y rs Dy a cp o a n mi r g mmi g A g r h r n l o i m Cu o d p o lm C mpe e re t b i rb e o lx d g e

【java】矩阵的最大子矩阵(动态规划)

【java】矩阵的最大子矩阵(动态规划)

【java】矩阵的最⼤⼦矩阵(动态规划)⼀、实验⽬的练习使⽤动态规划算法解决实际问题(使⽤Java语⾔实现)。

⼆、实验内容【问题描述】有⼀个包含正数和负数的⼆维数组。

⼀个⼦矩阵是指在该⼆维数组⾥,任意相邻的下标是1*1或更⼤的⼦数组。

⼀个⼦矩阵的和是指该⼦矩阵中所有元素的和。

本题中,把具有最⼤和的⼦矩阵称为最⼤⼦矩阵。

【⽰例】给出以下⼆维数组:0 -2 -7 09 2 -6 2-4 1 -4 1-1 8 0 -2这个数组的最⼤⼦矩阵为:9 2-4 1-1 8其和为15。

【输⼊】输⼊包含多组测试数据。

每组输⼊的第⼀⾏是⼀个正整数N(1<=N<=100),表⽰⼆维⽅阵的⼤⼩。

接下来N⾏每⾏输⼊N个整数,表⽰数组元素,范围为[-127,127]。

【输出】输出最⼤⼦矩阵和。

【思路提⽰】求最⼤⼦矩阵和问题是求最⼤⼦段和问题在⼆维空间上的推⼴,可参考求最⼤⼦段和问题。

三、 程序代码(1)maxSumList1package maxSumList;2import java.util.Scanner;34public class maxList{5 //public static int[][] list=new int[10][10];6 static int n;7 private maxSingleList maxSingleList=new maxSingleList();8 private final maxSingleList[] maxSingleLists;9 private int numberOfmaxSingleLists;1011 public maxList() {12 //创建计算每个⼦段和的类的数组13 maxSingleLists=new maxSingleList[100];14 }15161617 public void InputList(int[][] list){1819 System.out.println("请输⼊⽅阵⼤⼩:");20 Scanner scanner=new Scanner(System.in);21 n=scanner.nextInt();22 for (int y=0;y<n;y++){23 System.out.println("请输⼊⽅阵第"+(y+1)+"⾏数据:");24 for (int x=0;x<n;x++)25 list[y][x]=scanner.nextInt();26 }27 }28 public void OutputMaxSumList(int[][] list){29 int m=0;30 int max=0;31 int max1=0;32 int maxnum=0;3334 for (m=0;m<=numberOfmaxSingleLists;m++) {35 max1=maxSingleLists[m].getSum();36 if (max1 > max) {37 max = max1;38 maxnum = m;39 }40 }41 System.out.println("请输出最⼤⼦段和:"+maxSingleLists[maxnum].getSum());42 System.out.println("请输出最⼤⼦段:");43 for(int i=maxSingleLists[maxnum].getY1();i<=maxSingleLists[maxnum].getY2();i++){44 for (int j=maxSingleLists[maxnum].getNum1();j<=maxSingleLists[maxnum].getNum2();j++){45 System.out.print(list[i][j]+" ");46 }47 System.out.println("\n");48 }49 }5051 public void subMaxList(int[][] matrix) {52 int m=0;53 int[][] total = new int[10][10];54 for (int y=0;y<n;y++){55 for (int x=0;x<n;x++)56 total[y][x]=matrix[y][x];57 }585960 for (int i = 1; i < n; i++) {61 for (int j = 0; j < n; j++) {62 total[i][j] += total[i-1][j];63 }64 }6566 int maximum = 0;//Integer.MIN_VALUE;67 for (int i = 0; i < n; i++) {//所在的list⾏68 for (int j = i; j <n; j++) {//相差的69 //result 保存的是从 i ⾏到第 j ⾏所对应的矩阵上下值的和70 int[] result = new int[matrix[0].length];//每次都重新定义存放⼦段和的结果数组71 for (int f = 0; f < n; f++) {72 if (i == 0) {73 result[f] = total[j][f];74 } else {75 result[f] = total[j][f] - total[i - 1][f];76 }77 }78 maxSingleList maxSingleList=new maxSingleList();79 int maximal=maxSingleList.MaxListNum(result,i,j);80 numberOfmaxSingleLists=m;81 maxSingleLists[m++]= maxSingleList;81 maxSingleLists[m++]= maxSingleList;82 if (maximal > maximum) {83 maximum = maximal;84 }85 }86 }87 }8889}(2)maxSingleList4 private int num1;5 private int num2;6 private int y1;7 private int y2;8 private int sum;9 public int getNum1(){10 return num1;11 }12 public int getNum2(){13 return num2;14 }15 public void setY1(int y11){16 y1=y11;17 }18 public void setY2(int y22){19 y2=y22;20 }21 public int getY1(){22 return y1;23 }24 public int getY2(){25 return y2;26 }27 public void setSum(int sum){28 this.sum=sum;29 }30 public int getSum(){31 return sum;32 }33 public int MaxListNum(int[] array,int i,int j){34 int number,b=0,begin=0,bestmin=0,bestmax=0;35 sum=0;36 for (number = 0; number < array.length; number++) {//sum没清零37 if (b >= 0)//去掉等号38 b += array[number];39 else {40 b = array[number];41 begin = number;42 }43 if (b > sum) {//加个+44 sum = b;45 bestmin = begin;46 bestmax = number;47 }4849 }50 num1 = bestmin;51 num2= bestmax;52 setSum(sum);53 setY1(i);54 setY2(j);55 return sum;56 // if (sum==0)和为0的⾏数组要去掉那⼀⾏5758 }5960 }(3)TestmMaxList4 public static int[][] list=new int[10][10];5 public static void main(String[] arg){6 maxList maxlist=new maxList();7 maxlist.InputList(list);8 maxlist.subMaxList(list);9 maxlist.OutputMaxSumList(list); 1011 }12}四、 实验结果(含程序运⾏截图)五、 出现问题及解决⽅法(⼀)出现的问题在于算法的设计上,⼀开始我认为最⼤⼦矩阵就是每⾏所构成的最⼤⼦段的⾏列的序号交集,后来发现不是这样的,这样没办法正确输出最⼤⼦矩阵,得到的结果不对,然后推翻⾃⼰写了⼀天的代码以及想法。

动态规划——最大子段和

动态规划——最大子段和

动态规划——最⼤⼦段和⼀、最⼤⼦段和问题给定N个数A1, A2, ... An,从中选出k(k不固定)个连续的数字 Ai, Ai+1, ... Ai+k-1,使得∑i+k−1iAt 达到最⼤,求该最⼤值。

分析求最⼤⼦段和可以⽤多种算法来解决.(1)直接枚举max = 0;for i in [1...n]for j in [i....n]sum = 0;for k in [i...j]sum += A[k]if(sum > max)max = sum//时间复杂度为O(n^3)(2)求 sum[i...j]时,直接利⽤ sum[i...j] = sum[i...j-1] + A[j]来优化max = 0;for i in [1...n]sum = 0for j in [i....n]sum += A[j]if(sum > max)max = sum//时间复杂度为O(n^2)(3)分治法将A1...An⽤⼆分法分为左右两边,则A1...An中的最⼤连续⼦段和可能为三种情况:【1】是A1...An/2中的最⼤连续⼦段和【2】是An/2+1....An中的最⼤连续⼦段和【3】横跨左右两边int MaxSum(int* a, int beg, int end){if (beg == end){return a[beg] > 0? a[beg] :0;}int mid = (beg + end) / 2;int max_left = MaxSum(a, beg, mid);int max_right = MaxSum(a, mid + 1 ,end);int s1 = 0, s2 = 0, m_left = 0, m_right = 0;for(int i = mid; i <= beg; i --){s1 += a[i];if(s1 > m_left)m_left = s1;}for(int i = mid+1; i <= end; i ++){s2 += a[i];if(s2 > m_right)m_right = s2;}int max_sum = max_left;if(max_right > max_sum)max_sum = max_right;if(m_right + m_left > max_sum)max_sum = m_left + m_right;return max_sum;}//时间复杂度为 O(nlogn)(4)动态规划算法⽤动归数组 dp[i]表⽰以Ai结尾的若⼲个连续⼦段的和的最⼤值,则有递推公式:dp[i] = max{dp[i-1] + A[i], A[i]}int max = 0;for(int i = 1; i <= n; i ++){if(dp[i-1] > 0){dp[i] = dp[i-1] + A[i];}else{dp[i] = A[i];}if(dp[i]> max){max = dp[i];}}//时间复杂度为O(n)⼆、最⼤⼦矩阵和问题给定MxN的矩阵,其⼦矩阵R{x1, y1, x2, y2} (x1, y1) 为矩阵左上⾓的坐标,(x2, y2)为矩阵右下⾓的坐标,S(x1,y1,x2,y2)表⽰⼦矩阵R中的数字的和,求所有⼦矩阵的和的最⼤值。

怎么求数组的最大子序列和

怎么求数组的最大子序列和

怎么求数组的最大子序列和如何求解数组的最大子序列和在计算机科学和算法设计中,求解数组的最大子序列和是一个常见的问题。

给定一个整数数组,我们的目标是找到一个连续子数组,使得子数组的和最大。

本文将介绍两种常见的解决方法,并分析它们的时间复杂度和空间复杂度。

方法一:暴力法最简单直观的方法是使用两层循环遍历所有可能的子数组,计算它们的和,并记录下最大的和。

具体步骤如下:1. 初始化一个变量maxSum为数组中第一个元素的值,用于记录最大子序列和。

2. 通过两层循环遍历所有可能的子数组:a. 外层循环从0到n-1遍历数组的起始位置。

b. 内层循环从外层循环的当前位置到n-1遍历数组的结束位置。

c. 在内层循环中,计算当前子数组的和,并将其与maxSum比较,如果大于maxSum,则更新maxSum的值。

3. 返回maxSum作为最大子序列和。

这种方法的时间复杂度为O(n^2),因为我们需要遍历所有可能的子数组。

空间复杂度为O(1),因为我们只需要常数级别的额外空间。

方法二:动态规划动态规划是一种通过将原问题分解为子问题来求解的方法。

对于数组的最大子序列和,我们可以定义一个状态数组dp,其中dp[i]表示以第i个元素结尾的子数组的最大和。

具体步骤如下:1. 初始化一个状态数组dp,长度为n。

2. 初始化dp[0]为数组的第一个元素的值。

3. 从1到n-1遍历数组,对于每个元素arr[i],更新dp[i]的值为max(arr[i], dp[i-1]+arr[i])。

4. 最终的最大子序列和为dp数组中的最大值。

这种方法的时间复杂度为O(n),因为我们只需要遍历一次数组。

空间复杂度为O(n),因为我们需要一个长度为n的状态数组。

对比两种方法,动态规划方法具有更低的时间复杂度和更好的空间复杂度。

因此,在实际应用中,我们通常使用动态规划来求解数组的最大子序列和问题。

除了上述两种方法,还有其他一些优化的方法,如分治法和贪心法。

最大字段和的五种解法

最大字段和的五种解法

最大字段和的五种解法一、最大字段和的五种解法嘿,宝子们!今天咱们来唠唠最大字段和这个事儿的五种解法。

这可就像在一个充满宝藏的迷宫里找不同的出口一样有趣呢。

解法一:暴力枚举法咱就简单粗暴地把所有可能的字段和都计算出来。

比如说,给你一个数组,那咱们就从第一个数开始,依次往后加,得到一个和,然后再从第二个数开始,往后加,又得到一个和,就这么把所有可能的组合的和都算出来。

这就像是在一堆糖果里,一颗一颗地试哪种组合最甜。

不过这种方法呢,虽然简单直接,但是效率可有点低哦,特别是数组比较大的时候,就像要数一大袋子糖果,那可得花不少时间呢。

解法二:分治法这个方法就有点高级啦。

我们把这个数组分成两部分,然后分别求出左边部分的最大字段和、右边部分的最大字段和,还有横跨中间部分的最大字段和。

最后呢,从这三个和里面挑出最大的那个。

这就像是把一个大蛋糕切成两块,然后分别在两块蛋糕里找最大的草莓,再看看横跨两块蛋糕的地方有没有更大的草莓。

这样算起来就比暴力枚举法快多啦。

解法三:动态规划法这个动态规划可有意思了。

我们定义一个数组,这个数组的每个元素都表示从第一个数到这个数的最大字段和。

然后我们通过一个递推公式来计算这个数组。

就好像是搭积木一样,一块一块地往上搭,每一块都依赖于前面的几块。

这样我们就能很高效地算出最大字段和啦。

这就像是在盖房子,每一层都要根据下面的几层来建造,最后房子就稳稳地盖好啦。

解法四:贪心算法贪心算法就是每次都选择当前看起来最优的选择。

对于最大字段和来说,我们从数组的开头开始,只要当前的和是正数,我们就继续往后加。

如果当前的和变成负数了,那我们就重新开始计算新的字段和。

这就像是在走迷宫的时候,每次都选择看起来最能接近出口的路。

不过这种方法有时候可能不是全局最优的,但是在很多情况下都能很快地得到一个比较好的结果。

解法五:优化的暴力枚举法这个方法呢,其实就是在暴力枚举法的基础上做了一些优化。

我们可以利用一些数学上的小技巧,比如如果前面的和已经比我们已经找到的最大字段和小了,那我们就不用再继续往后加了。

动态规划:最大子矩阵

动态规划:最大子矩阵

动态规划:最⼤⼦矩阵 在DP问题中有⼀种叫最⼤⼦矩阵问题,刚好碰到了这⼀题,于是学习分享之。

让我们先来看⼀下题⽬:ZOJ Problem Set - 1074 题⽬分类:动态规划 题⽬⼤意:就是输⼊⼀个N*N的矩阵,找出在矩阵中,所有元素加起来之和最⼤的⼦矩阵。

例如在 0 -2 -7 0 这样⼀个4*4的矩阵中,元素之和最⼤的⼦矩阵为 9 2 ,它们之和为15。

  9 2 -6 2 -4 1 -4 1 -4 1 -1 8 -1 8 0 -2 这是⼀个最⼤⼦矩阵问题,我们怎么来解决这个问题呢?任何问题都会有它的简化的问题,这是⼆维的数组,与之对应的,我们可以先尝试⼀下⼀维数组。

如果有⼀个⼀维数组a[n],如何找出连续的⼀段,使其元素之和最⼤呢? 例如有 1 2 -3 4 -2 5 -3 -1 7 4 -6 这样⼀个数组,那么显然 4 -2 5 -3 -1 7 4 这个⼦数组元素之和最⼤,为4+(-2)+5+(-3)+(-3)+7+4=14。

为找到⼀维数组的最⼤⼦数组,我们可以有以下⽅法。

1、穷举法1for(i=0;i<n;i++)2 {3for(j=0;j<=i;j++)4 {5 sum = 0;6for(k=j;k<=i;k++)7 sum += a[k];8if(sum > max) max = sum;9 }10 } 穷举法在n很⼤的情况下,需要运⾏的次数⾮常的多,有三层循环,所以n很⼤时不能使⽤这种⽅法。

2、带记忆的递推法1 record[0] = 0;2for(i=1;i<=n;i++) //⽤下标1~n来储存n个数3 record[i] = record[i-1] + a[i]; //⽤record记录a[i]前i个的和4 max = 0;5for(i=1;i<=n;i++)6 {7for(j=0;j<i;j++)8 {9 sum = record[i] - record[j];10if(sum > max) max = sum;11 }12 } 这种⽅法的时间复杂度明显⽐上⼀种的低了很多,时间复杂度为O(n²)。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

-4 6 6 9 9
其最大子矩阵为: 9 2
其最大子矩阵为: -5 6
其元素总和为11。
7 9
其元素总和为17。
动态规划法:
动态规划法其实就是把二维最大子段和转化为 一维最大子段和问题。 转化方法: 我们把这个矩阵划分成n个“条”,条的长度为1到 m,通过两个for遍历所有长度的条。 然后,若干个连续的条,就是一个子矩阵了,这样 问题就轻易地转化为一维最大子段和问题了。 通过求所有这种条,起点为i,长度为1到m-i+1的 “条”的最大子段和,就可以求出整个矩阵的最大 子矩阵了。
12
子段和问题的扩展—2维最大子段和
二维最大子段和问题又称为最大子矩阵问题,给定一 个m行n列的整数矩阵a,试求矩阵a的一个子矩阵,使 其各元素之和为最大。 即 s (i1, i 2, j1, j 2) a[i ][ j ]
i i1 j j1 i2 j2
最大子矩阵和问题的最优值为 1maxm s(i1, i 2, j1, j 2) i1i 2
• 动态规划有很强的阶段递推思想,用前一段存储的计算结果,递
推后一阶段的结果,是一种全面继承前期信息的方法。
9
算法设计:
记 sum为a[1] ~a[j]的最大子段和,记b[j]为当前子段和。

b[ j ] max{ a[k ]}
1 i j k i j
,1 j n。
当b[j-1]>0时,前面子段的和对总和有贡献,所以要累加前
6
对于情形(3)。容易看出,序列元素a[(n/2)]与 a[(n/2)+1]一定在最优子序列中。因此,可以计算出
a[i:(n/2)]的最大值s1;并计算出a[(n/2)+1:j]中的最大值
s2。则s1+s2即为出现情形(3)时的最优值。据此可设计 出求最大子段和的分治算法。
7
算法如下:
int maxsum(int a[], int left, int right) s1 = 0; //处理情形(3) { lefts = 0; int sum = 0,leftsum,rightsum; for (i = center; i >= 1; i--) int i,j; { lefts += a[i]; int lefts,rights; if (lefts > s1) s1 = lefts; } int s1,s2; s2 = 0; int center; rights = 0; if (1 == n) 复杂度分析 for (j = center + 1; j <= n; j++) { { rights += a[j]; if (a[1] > 0) O(1) n c if (rights > s2) s2 = rights; } sum = a[1]; T (n) sum = s1 + s2; 2T (n / 2) O(n) n c if (sum < leftsum) else sum = 0; } sum = leftsum; T(n)=O(nlogn) else if (sum < rightsum) { sum = rightsum; center = (1 + n) / 2; } leftsum = maxsum(a,1, center); return sum; rightsum = maxsum(a,center + 1, }*/ n);
算法说明: 1、算法中的thissum代表 当前子段和,即a[i]到a[j]多 有元素的和;sum代表函数 结束时存储的最大子段和。 besti代表最大子段和的起 点下标,bestj代表代表最 大子段和的终点下标。 2、时间复杂度为O(n3).
4
改进的枚举算法设计
public static int MaxSubsum(int a[]){ int sum = 0; int besti; int bestj; for (int i=0;i<a.length;i++) { int thissum=0; for (int j=i;j<a.length;j++) { thissum+=a[j]; thissum+=a[j]; if (thissum>sum) { sum=thissum; besti=i+1; bestj=j+1; } } } return sum; }
①当m=1时,
则该问题变为求最大字段和的问题
②当m>1时
设b(i,j)表示前j个元素(必定包含第j个元素)分为互不相交的i段所 得的最大i子段和并且i<=j。 (注:b(i,j)不一定是最优最大i子段和) 因此在考虑第j个元素时,可能存在两种情况: 1)第j个元素和前一个元素一起包含在第i段中; 2)第j个元素独自划分在第i段中。 根据问题的分析,两种情况分别如下: 1)b(i,j-1)表示第j-1个元素的最大j子段和,所以b(i,j)=b(i,j-1)+a[j]. 2)max{b(i-1,k)}其中k=i-1..j-1.即表示为在第j个元素之前得到的 i-1个子段之和的最优选择。所以b(i,j)=max{b(i-1,k)+a[j]},其中k=i1..j-1. 综上:b(i,j)=max{b(i,j-1)+a[j],max b(i-1,k)+a[j]},其中k=i-1..j-1.
面的值。b[j]=b[j-1]+a[j],当b[j-1] 0时,前面子段的和对总 和没有贡献,要重新累加, b[j] =a[j]。由此可得计算b[j]的动 态规划递归式b[j]=max{b[j-1]+a[j],a[j]}, 1 j n。
10
举例:
k a[k] 1 3 2 -4 3 2 4 10 5 1
最大子段和问题
钱能武
030130733
1
讲课的主要内容:
• • • • • • 问题描述 最大子段和问题的简单算法以及改进算法(枚举/穷举) 最大子段和问题的分治算法 最大子段和问题的动态规划算法 推广1:最大子矩阵问题 推广2:最大m字段和问题算法及改进算法
补充内容:动态规划算法步骤 1、找出最优解的性质,并刻画其结构特征 2、递归地定义最优值 3、以自底向上的方式计算最优值 4、根据计算最优值时得到的信息结构最优解
b[k]
3
-1
2
12
13
其中: b[1]=a[1]=3, b[2]=b[1]+a[2]=-1, b[3]=a[3]=2, b[4]=b[3]+a[4] =12, b[5]=b[4]+a[5] =13; 因此,对于数组a 而言,最大子段和为b[5], 即sum=13。
11
程序实现:
public static int MaxSubsum(int a[],int n){ int sum = 0,b = 0; 这已经是一个简化后的算法,最基本的 for(int i=0;i<n;i++){ 做法其实可以申请一个b[n]数组,每次 if(b>0){ 求解b[j]=max{b[j-1]+a[j],a[j]} ,最后 b+=a[i]; } 遍历b[n]求得最大数组即可。 else b = a[i]; if(b>sum){ sum = b; } } 动态规划法的计算时间复杂度为O(n) return sum; }
5
由 i ak a j i ak 知第k次计算 k kjj 1来自的的和可由k-1次的结果
递推。 算法1每次都从 头开始累加,则可将算 法中的最内层一个for循 环省去,避免重复计算。
改进后的算法只需要O(n2)的计算时间
2、分治算法
经过以上改进只是减少了i一定时的重复计算操 作。其中仍会有很多重复计算。从这个问题结构可以 看出,它适合于用分治法求解。 如果将所给的序列a[1:n]分为长度相等的2段 a[1:n/2]和a[n/2+1:n],分别求出这2段的最大子段和, 则a[1:n]的最大子段和有3种情行。 (1)a[1:n]的最大子段和与a[1:(n/2)]最大子 段和相同; (2)a[1:n]的最大子段和与a[(n/2)+1:n]最大 子段和相同; 情形(1)、(2)可递归求得。 (3)a[1:n]的最大子段和为 , 且1≤i≤n/2,(n/2)+1≤j≤n。
16
具体枚举长条的时候,同一起点的长度,由于“条”的不 同长度间可以利用之前的结果。 比如令b[k][i][j]表示第k个长“条”区间从i到j的和,那么 b[k][i][j+1] = b[k][i][j]+a[j][k]。 当然,实际编程的时候,由于之前的结果求完一维最大子 段和后,便不需要保存,所以只需要一维数组b即可。
17
参考代码
public static int MaxSum(int a[][],int m,int n){ int sum = 0; int b[] =new int[n]; for(int i = 0;i < m;i++){ for(int k = 0;k < n;k++) b[k] = 0; for(int j = i;j <m;j++){ for(int k = 0;k < n;k++) b[k]+=a[j][k]; int max = MaxSubsum(b,n); if(max > sum) sum = max; } } return sum; } 由于MaxSubsum()需要 O(n)的时间,估此算法 的双重for循环需要
8
3、动态规划算法
分治法减少了各分组之间的一些重复计算,但由于分解后的问题 不独立,在情形(3)中重复计算较多,还是没有充分运用前期的计 算结果。动态规划的特长就是解决分解的子问题不独立的情况。 • 动态规划的思路就是通过开辟存储空间,存储各子问题的计算结 果,从而避免重复计算。其实就是用空间效率去换取时间效率。
相关文档
最新文档