**一、最大子段和**
给定n(1<=n<=100000)个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时定义子段和为0,依此定义,所求的最优值为: Max{0,a[i]+a[i+1]+…+a[j]},1<=i<=j<=n。
 例如,当(a[1],a[2],a[3],a[4],a[5],a[6])=(-2,11,-4,13,-5,-2)时,最大子段和为20.
 
 动态规划法  复杂度O(n)。

int max(int a[],int n)
{
    int sum,maxsum;
    int i ;
    sum = maxsum = 0;
    for(i = 0;i<n;i++)
    {
        sum +=a[i];
        if(sum>maxsum)
            maxsum = sum;
        else if(sum<0)
            sum = 0;
    }
    return maxsum;
}

**二、最长递增子序列**
给定一个序列,求解它的最长 递增 子序列 的长度。比如: arr[] = {3,1,4,1,5,9,2,6,5}   的最长递增子序列长度为4。即为:1,4,5,9
赋初值很重要!!!!!!!!!
标志性的双重循环以及内层循环的范围,公式:dp[i]=max(dp[j]+a[i],dp[i])

#include<stdio.h>
//最长增长子序列 
#define max(x,y) x>y? x:y
int main()
{
	int i,j,n;
	scanf("%d",&n);
	int a[10005];
	int b[10005];
	for(i=0;i<n;i++)
	{
		scanf("%d",&a[i]); 
		b[i]=1;
	}
	for(i=1;i<n;i++)
	{
		for(j=0;j<i;j++)   //格式!!!!里面的for循环范围是0到i-1,目的是寻找i之前的量中,是否有符合要求的量
		{
			if(a[i]<a[j])
			{
				b[i]=max(b[j]+1,b[i]);   //记住,公式:dp[i]=max(dp[j]+a[i],dp[i])  这里的b相当于dp,1相当于a,注意公式中的下标的区别!!!!!!!!!
			}
		}
	 } 
	 int max;
	printf("%d\n",*max_element(b,b+n));  //寻找数组中的最大值,头文件是algorithm.
}

## 例题
 **Super Jumping! Jumping! Jumping!** 
 Nowadays, a kind of chess game called “Super Jumping! Jumping! Jumping!” is very popular in HDU. Maybe you are a good boy, and know little about this game, so I introduce it to you now. 

最大子段和、最长单调递增子序列、最长公共子序列

The game can be played by two or more than two players. It consists of a chessboard(棋盘)and some chessmen(棋子), and all chessmen are marked by a positive integer or “start” or “end”. The player starts from start-point and must jumps into end-point finally. In the course of jumping, the player will visit the chessmen in the path, but everyone must jumps from one chessman to another absolutely bigger (you can assume start-point is a minimum and end-point is a maximum.). And all players cannot go backwards. One jumping can go from a chessman to next, also can go across many chessmen, and even you can straightly get to end-point from start-point. Of course you get zero point in this situation. A player is a winner if and only if he can get a bigger score according to his jumping solution. Note that your score comes from the sum of value on the chessmen in you jumping path. 
Your task is to output the maximum value according to the given chessmen list. 
Input
Input contains multiple test cases. Each test case is described in a line as follow:
N value_1 value_2 …value_N 
It is guarantied that N is not more than 1000 and all value_i are in the range of 32-int. 
A test case starting with 0 terminates the input and this test case is not to be processed. 
**Output**
For each case, print the maximum according to rules, and one line one case. 
**Sample Input**
3 1 3 2
4 1 2 3 4
4 3 3 2 1
0
**Sample Output**
4
10
3

虽然是求最大值,但也是最长递增子序列问题
 

#include <stdio.h>
#include <string.h>
#include<algorithm>
using namespace std;
int num[1010],dp[1010];
int main ()
{
    int n;
    while (~scanf("%d",&n)&&n)
    {
        for (int i=0;i<n;i++)
        {
            scanf("%d",&num[i]);
        }
        for(int i=0;i<n;i++)   //初始化!!!!!!
            dp[i]=num[i];
        for (int i=1;i<n;i++)
        {
            for (int j=0;j<i;j++)   //双重for!!!!!!!!
            {
                if (num[i]>num[j])
                dp[i]=max(dp[i],dp[j]+num[i]);   //公式!!!!!!!!!!
            }
        }
        printf ("%d\n",*max_element(dp,dp+n));
    }
    return 0;
}

 

**三 最长公共子序列**
典型的dp模型
给定两个字符串,求解这两个字符串的最长公共子序列(最长公共序列)比如字符串1:BDCABA;字符串2:ABCBDAB
则这两个字符串的最长公共子序列长度为4,最长公共子序列是:BCBA

1)如果xn = ym,即X的最后一个元素与Y的最后一个元素相同,这说明该元素一定位于公共子序列中。因此,现在只需要找:LCS(Xn-1,Ym-1)
2)如果xn!= ym,就不用考虑最后两个数相等,这时分两种情况继续讨论,一种是删掉xn,一种是删掉yn,再继续对比末尾的两个值,产生了两个子问题:LCS(Xn-1,Ym)和LCS(Xn,Ym-1)。

重叠子问题:
原问题是:LCS(X,Y)子问题有❶LCS(XN-1,YM-1)❷LCS(XN-1,YM)❸LCS(XN,YM-1)
其中:LCS(XN-1,YM)就包含了:问题❶LCS(XN-1,YM-1)。因为当XN-1和YM的最后一个元素不相同时,我们又需要将LCS(XN-1,YM)进行分解:分解成:LCS(XN-1,YM-1)和LCS(XN-2 ),YM)。所以这里要用到dp


公式:

最大子段和、最长单调递增子序列、最长公共子序列

最大子段和、最长单调递增子序列、最长公共子序列

赋初值很重要!!如图,通常是将没有值的地方赋为0 

例题:
**Common Subsequence** 
A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = <x1, x2, ..., xm> another sequence Z = <z1, z2, ..., zk> is a subsequence of X if there exists a strictly increasing sequence <i1, i2, ..., ik> of indices of X such that for all j = 1,2,...,k, xij = zj. For example, Z = <a, b, f, c> is a subsequence of X = <a, b, c, f, b, c> with index sequence <1, 2, 4, 6>. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y. 
The program input is from a text file. Each data set in the file contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct. For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line. 
**Input**
abcfbc abfcab
programming contest 
abcd mnp
**Output**
4
2
0
**Sample Input**
abcfbc abfcab
programming contest 
abcd mnp
**Sample Output**
4
2
0

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[1000][1000];
int main()
{
    char a[1000],b[1000];
    int x,y;
    while(~scanf("%s %s",a,b))
    {
        x=strlen(a);
        y=strlen(b);
         for(int i=0;i<=x;i++)
         {
             for(int j=0;j<=y;j++)
             {
                 if(i==0||j==0) 
                    dp[i][j]=0;
                 else if(a[i-1]==b[j-1])   //将字符数组的下标-1,可以实现数组从1到x或y存在(实际是从0到x-1或y-1),为了将两排0空出来赋初值。
                     dp[i][j]=dp[i-1][j-1]+1;
                 else
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
             }
         }printf("%d\n",dp[x][y]);
    }
}

 

相关文章: