2024年春季学期《算法分析与设计》练习8

目录

问题 A: 最长公共子序列问题(LCS)之备忘录法

问题 B: 最长公共子序列问题(LCS)之动态规划法 

问题 C: 最长公共子序列问题(LCS)-构造LCS

问题 D: 牛牛的字符串

问题 E: 最大子段和

问题 F: 最大子段和升级版


问题 A: 最长公共子序列问题(LCS)之备忘录法

题目描述
使用备忘录法求解两个序列的最长公共子序列的长度。
输入
每组输入包括两行,每行包括一个字符串。
输出

两个序列的最长公共子序列的长度。

样例输入 Copy
<span style="background-color:#ffffff"><span style="color:#333333"><span style="color:#333333"><span style="background-color:#f5f5f5">ACBCDABD
ABDCABA</span></span></span></span>
样例输出 Copy
<span style="background-color:#ffffff"><span style="color:#333333"><span style="color:#333333"><span style="background-color:#f5f5f5">5</span></span></span></span>
#include<stdio.h>
#include<string.h>

int max(int a,int b){
	return a>=b?a:b;
}

int lsc(char x[],char y[],int i,int j){
	if(i==0||j==0) return 0;
	if(x[i-1]==y[j-1])
		return lsc(x,y,i-1,j-1)+1;
	else
		return max(lsc(x,y,i,j-1),lsc(x,y,i-1,j));
}
int main(){
	char a[100],b[100];
	int str1,str2,s=0;
	scanf("%s",a);
	scanf("%s",b);
	str1=strlen(a);
	str2=strlen(b);
	s=lsc(a,b,str1,str2);
	printf("%d\n",s);
}

问题 B: 最长公共子序列问题(LCS)之动态规划法 

题目描述

使用动态规划算法求解两个序列的最长公共子序列的长度。

输入

每组输入包括两行,每行包括一个字符串。

输出

两个序列的最长公共子序列的长度。

样例输入 Copy
ACBCDABD
ABDCABA
样例输出 Copy
5
#include<stdio.h>
#include<string.h>

int lsc(char x[],char y[],int m,int n){
	int a[100][100];
	int i,j;
	for(i=0;i<m;i++) a[i][0]=0;
	for(j=0;j<n;j++) a[0][j]=0;
	for(i=1;i<=m;i++){
		for(j=1;j<=n;j++){
			if(x[i-1]==y[j-1])
				a[i][j]=a[i-1][j-1]+1;
			else 
				a[i][j]=a[i-1][j]>=a[i][j-1]?a[i-1][j]:a[i][j-1];
		}
	}
	return a[m][n];
}
int main(){
	char a[100],b[100];
	int str1,str2,s=0;
	scanf("%s",a);
	scanf("%s",b);
	str1=strlen(a);
	str2=strlen(b);
	s=lsc(a,b,str1,str2);
	printf("%d\n",s);
}

问题 C: 最长公共子序列问题(LCS)-构造LCS

题目描述

使用动态规划算法求两个序列的最长公共子序列,需构造一条最长公共子序列。

输入

每组输入包括两行,每行包括一个字符串。

输出

两个字符序列的一条最长公共子序列。(输入已确保最长公共子序列的唯一性)

样例输入 Copy
acdbxx
ccdxx
样例输出 Copy
cdxx
#include<stdio.h>
#include<string.h>

int s[100][100];

void lcslen(char x[],char y[],int m,int n){
	int a[100][100];
	int i,j;
	 // 初始化a数组和b数组 
	for(i=0;i<m;i++) a[i][0]=0;
	for(j=0;j<n;j++) a[0][j]=0;
	// 动态规划计算LCS长度和路径  
	for(i=1;i<=m;i++){
		for(j=1;j<=n;j++){
			if(x[i-1]==y[j-1]){
				a[i][j]=a[i-1][j-1]+1;
				s[i][j]=1;// 表示当前字符来自x和y的当前位置
			}else if(a[i-1][j]>=a[i][j-1]){
				a[i][j]=a[i-1][j];
				s[i][j]=2; // 表示当前字符来自x的上一位置
			}else{
				a[i][j]=a[i][j-1];
				s[i][j]=3;// 表示当前字符来自y的上一位置 
			}
		}
	}
}

void lcs(int i,int j,char x[]){
	if(i==0||j==0) return ;
	if(s[i][j]==1){
		lcs(i-1,j-1,x);
		printf("%c",x[i-1]);
	}else if(s[i][j]==2) lcs(i-1,j,x);
	else lcs(i,j-1,x);
		
}
int main(){
	char a[100],b[100];
	int str1,str2;
	scanf("%s",a);
	scanf("%s",b);
	str1=strlen(a);
	str2=strlen(b);
	lcslen(a,b,str1,str2);
	lcs(str1,str2,a);
	printf("\n");
}

问题 D: 牛牛的字符串

题目描述

牛牛有两个字符串(可能包含空格),他想找出其中最长的公共连续子串的长度,希望你能帮助他。例如:两个字符串分别为"abede"和"abgde",结果为2。

输入

每组数据包括两行,每行为一个字符串。

输出

输出最长的公共连续子串的长度。

样例输入 Copy
abede
abgde
样例输出 Copy
2
#include<stdio.h>

int lcs(char x[],char y[],int m,int n){
	int dp[100][100];
	int i,j;
	int a=0;
	for(i=0;i<m;i++){
		if(x[i]==y[0])
			dp[i][0]=1;
	}
	for(j=1;j<n;j++){
		if(x[0]==y[j])
			dp[0][j]=1;
	} 
	for(i=1;i<m;i++){
		for(j=1;j<n;j++){
			if(x[i]==y[j]){
				dp[i][j]=dp[i-1][j-1]+1;
				a=a>=dp[i][j]?a:dp[i][j];
			}
		}
	}
	return a;
}

int main(){
	char a[100],b[100];
	int str1,str2;
	scanf("%s",a);
	scanf("%s",b);
	str1=strlen(a);
	str2=strlen(b);
	printf("%d\n",lcs(a,b,str1,str2));
}

问题 E: 最大子段和

题目描述

给定n个整数(可能是负数)组成的序列a[1], a[2], a[3], …, a[n],求该序列的子段和如a[i]+a[i+1]+…+a[j]的最大值。

输入

每组输入包括两行,第一行为序列长度n,第二行为序列。

输出

输出字段和的最大值。

样例输入 Copy
5
-1 0 1 2 3
样例输出 Copy
6
#include<stdio.h>

int solve(int a[],int n){
	int b[100]={0};
	int max,j;
	b[0]=a[0];
	max=b[0];
	for(j=1;j<n;j++){
		if(b[j-1]>0)
			b[j]=b[j-1]+a[j];
		else
			b[j]=a[j];
		if(b[j]>max)
			max=b[j];
	}
	return max;
}

int main(){
	int n,i;
	int a[100];
	while(~scanf("%d",&n)){
		for(i=0;i<n;i++){
			scanf("%d",&a[i]);
		}
		printf("%d\n",solve(a,n));
	}
}

问题 F: 最大子段和升级版

题目描述

使用动态规划算法求整数数组(可能包含负整数)的最大子段和,以及和最大子段的起始位置和结束位置:
例如:输入数组(6,-1,5,4,-7),输出14, 1, 4,其中14表示最大子段和,1表示和最大的子段从第1个数字开始,4表示和最大的子段到第4个数字结束,即(6, -1 , 5, 4)。

输入

每组输入两行,第1行为数组中包含的整数个数n,第2行为n个整数(可能包含负整数),两两之间用空格隔开。

输出

输出最大子段和,以及和最大子段的起始位置和结束位置,两两之间用空格隔开。

样例输入 Copy
5
6 -1 5 4 -7
样例输出 Copy
14 1 4
#include <stdio.h>
#include <stdlib.h>
 
int main (){
    int a[100],b[100];
    int n;
 
while(~scanf("%d",&n)){
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    b[0]=a[0];
    int max=b[0],j=0;
    for(int i=1;i<n;i++){
        if(b[i-1]>0) b[i]=b[i-1]+a[i];
        else b[i]=a[i];
        if(max<b[i]){
           max=b[i];
           j=i;
        }
     }
    int x=j;
    while(b[j]>=0&&j>=0)
         j--;
     printf("%d %d %d\n",max,j+2,x+1);
}
    return 0;
}
  • 24
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值