codeup 11.2~11.6 经典dp 练习

版权声明:原创文章,转载请注明出处 https://blog.csdn.net/hza419763578/article/details/88749838

参考博文

问题 A: 最大连续子序列

时间限制: 1 Sec  内存限制: 32 MB
提交: 422  解决: 185
[提交][状态][讨论版][命题人:外部导入]

题目描述

给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j <= K。最大连续子序列是所有连续子序列中元素和最大的一个,例如给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{ 11, -4, 13 },最大和为20。现在增加一个要求,即还需要输出该子序列的第一个和最后一个元素。

输入

测试输入包含若干测试用例,每个测试用例占2行,第1行给出正整数K( K<= 10000 ),第2行给出K个整数,中间用空格分隔,每个数的绝对值不超过100。当K为0时,输入结束,该用例不被处理。

输出

对每个测试用例,在1行里输出最大和、最大连续子序列的第一个和最后一个元素,中间用空格分隔。如果最大连续子序列不唯一,则输出序号i和j最小的那个(如输入样例的第2、3组)。若所有K个元素都是负数,则定义其最大和为0,输出整个序列的首尾元素。

样例输入

5
-3 9 -2 5 -4
3
-2 -3 -1
0

样例输出

12 9 5
0 -2 -1

提示


这是一道稍微有点难度的动态规划题。 

首先可以想到的做法是枚举每个区间的和,预处理sum[i]来表示区间[1, i]的和之后通过减法我们可以O(1)时间获得区间[i, j]的和,因此这个做法的时间复杂度为O(n^2)。 


然后这题的数据范围较大,因此还需作进一步优化才可以AC。记第i个元素为a[i],定义dp[i]表示以下标i结尾的区间的最大和,那么dp[i]的计算有2种选择,一种是含有a[i-1],一种是不含有a[i-1],前者的最大值为dp[i-1]+a[i],后者的最大值为a[i]。而两者取舍的区别在于dp[i-1]是否大于0。

#include<iostream>
using namespace std;

const int N=1e4+10;
int a[N],dp[N],Start[N];

int main(){
	// freopen("input1.txt","r",stdin);
	int n,Max,si,ei;//si是起点下标  ei是终点下标
	while(cin>>n&&n!=0){
		si=0,ei=n-1;
		for(int i=0;i<n;i++){
			cin>>a[i];
			Start[i]=i;//开始所有的起点下标都设为自己
		}
		Max=dp[0]=a[0];
		bool hasPos=false;
		for(int i=1;i<n;i++){
			if(dp[i-1]>=0){//起点下标i要最小 所以取等号
				hasPos=true;
				dp[i]=dp[i-1]+a[i];
				Start[i]=Start[i-1];//起点变了
			}else{
				dp[i]=a[i];//Start[i]就是自己 以自己为起点
			}

			if(Max<dp[i]){
				Max=dp[i];
				ei=i;//更新终点
			}

		}
		if(hasPos)//有正数
			cout<<Max<<" "<<a[Start[ei]]<<" "<<a[ei]<<endl;
		else cout<<0<<" "<<a[0]<<" "<<a[n-1]<<endl;
	}
	return 0;
}

问题 A: 最长上升子序列

时间限制: 2 Sec  内存限制: 64 MB
提交: 430  解决: 217
[提交][状态][讨论版][命题人:外部导入]

题目描述

一个数列ai如果满足条件a1 < a2 < ... < aN,那么它是一个有序的上升数列。我们取数列(a1a2, ..., aN)的任一子序列(ai1ai2, ..., aiK)使得1 <= i1 <i2 < ... < iK <= N。例如,数列(1, 7, 3, 5, 9, 4, 8)的有序上升子序列,像(1, 7), (3, 4, 8)和许多其他的子序列。在所有的子序列中,最长的上升子序列的长度是4,如(1, 3, 5, 8)。

    现在你要写一个程序,从给出的数列中找到它的最长上升子序列。

输入

输入包含两行,第一行只有一个整数N(1 <= N <= 1000),表示数列的长度。

第二行有N个自然数ai,0 <= ai <= 10000,两个数之间用空格隔开。

输出

输出只有一行,包含一个整数,表示最长上升子序列的长度。

样例输入

7
1 7 3 5 9 4 8

样例输出

4
#include<iostream>
using namespace std;

const int N=1e3+10;
int a[N],dp[N];

int main(){
	// freopen("input2.txt","r",stdin);
	int n,max;
	while(cin>>n){
		for(int i=0;i<n;i++){
			cin>>a[i];
		}
		max=0;
		for(int i=0;i<n;i++){
			dp[i]=1;
			for(int j=0;j<i;j++){
				if(a[j]<a[i]&&dp[j]+1>dp[i]){
					dp[i]=dp[j]+1;
				}
			}
			if(max<dp[i]) max=dp[i];
		}
		cout<<max<<endl;
	}
	return 0;
}

问题 A: 最长公共子序列

时间限制: 1 Sec  内存限制: 32 MB
提交: 355  解决: 199
[提交][状态][讨论版][命题人:外部导入]

题目描述

给你一个序列X和另一个序列Z,当Z中的所有元素都在X中存在,并且在X中的下标顺序是严格递增的,那么就把Z叫做X的子序列。
例如:Z=<a,b,f,c>是序列X=<a,b,c,f,b,c>的一个子序列,Z中的元素在X中的下标序列为<1,2,4,6>。
现给你两个序列X和Y,请问它们的最长公共子序列的长度是多少?

输入

输入包含多组测试数据。每组输入占一行,为两个字符串,由若干个空格分隔。每个字符串的长度不超过100。

输出

对于每组输入,输出两个字符串的最长公共子序列的长度。

样例输入

abcfbc abfcab
programming contest 
abcd mnp

样例输出

4
2
0
#include<iostream>
#include<string>
#include <algorithm>
using namespace std;

const int N=100+10;
int a[N],dp[N][N];

int main(){
	// freopen("input3.txt","r",stdin);
	string s1,s2;
	while(cin>>s1>>s2){
		s1=" "+s1;
		s2=" "+s2;
		for(int i=0;i<s1.length();i++){
			dp[i][0]=0;
		}
		for(int j=0;j<s2.length();j++){
			dp[0][j]=0;
		}
		for(int i=1;i<s1.length();i++){
			for(int j=1;j<s2.length();j++){
				if(s1[i]==s2[j]){
					dp[i][j]=dp[i-1][j-1]+1;//不要瞎写  abc  acc (ab&ac)+1=2
				}else{
					dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
				}
			}
		}
		//别忘记dp[i][j]的意义,直接输出dp[m][n]最长的两串即可 不必Max找最大
		cout<<dp[s1.length()-1][s2.length()-1]<<endl;

	}
	return 0;
}

问题 A: 【字符串】最长回文子串

时间限制: 1 Sec  内存限制: 128 MB
提交: 255  解决: 122
[提交][状态][讨论版][命题人:外部导入]

题目描述

        输入一个字符串,求出其中最长的回文子串。子串的含义是:在原串中连续出现的字符串片段。回文的含义是:正着看和倒着看相同。如abba和yyxyy。在判断回文时,应该忽略所有标点符号和空格,且忽略大小写,但输出应保持原样(在回文串的首部和尾部不要输出多余字符)。输入字符串长度不超过5000,且占据单独的一行。应该输出最长的回文串,如果有多个,输出起始位置最靠左的。

输入

一行字符串,字符串长度不超过5000。

输出

字符串中的最长回文子串。

样例输入

Confuciuss say:Madam,I'm Adam.

样例输出

Madam,I'm Adam

提示


样例说明:Madam,I'm Adam去掉空格、逗号、单引号、忽略大小写为MADAMIMADAM,是回文。

#include<iostream>
#include<string>
#include<cctype>
using namespace std;
string S;
const int N=5010;
char S1[N];
int Index[N];
int dp[N][N];

int main(){
	// freopen("input4.txt","r",stdin);
	int index,len,si,ei,max;
	while(getline(cin,S)){
		len=S.length();
		index=0;
		max=0;
		for(int i=0;i<len;i++){
			if(isalnum(S[i])){
				S1[index]=tolower(S[i]);
				Index[index]=i;//在原来字符串中的下标位置
				index++;
			}
		}
		//求S1最长回文子串
		//边界
		for(int i=0;i<index;i++){
			dp[i][i]=1;
			max=1;
			if(i<index-1&&S1[i]==S1[i+1]){
				dp[i][i+1]=1;
				max=2;
			}
		}

		//递归
		for(int L=3;L<=index;L++){
			for(int i=0;i+L-1<index;i++){
				int j=i+L-1;
				if(S1[i]==S1[j]){
					dp[i][j]=dp[i+1][j-1];//不是长度 只是0 1代表true和false
				}
				if(dp[i][j]==1){//越来越长 j-i+1=L L递增
					si=i,ei=j;
				}
			}
		}

		//输出
		si=Index[si];ei=Index[ei];
		cout<<S.substr(si,ei-si+1)<<endl;

	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/hza419763578/article/details/88749838
今日推荐