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

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

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

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

样例输入 Copy
ACBCDABD
ABDCABA
样例输出 Copy
5
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
string a,b;
int dp[N][N];
int lcs(int x,int y){
    if(dp[x][y]!=-1){
        return dp[x][y];
    }
    if(x==0||y==0){
        dp[x][y]=0;
    }
    else if(a[x-1]==b[y-1]){
        dp[x][y]=lcs(x-1,y-1)+1;
    }
    else{
        dp[x][y]=max(lcs(x,y-1),lcs(x-1,y));
    }
    return dp[x][y];
}
void solve(){
    cin>>a>>b;
    memset(dp,-1,sizeof dp);
    cout<<lcs(a.size(),b.size())<<"\n";
}
int main() {
    cin.tie(0)->sync_with_stdio(false);
    solve();
    return 0;
}

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

题目描述

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

输入

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

输出

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

样例输入 Copy
ACBCDABD
ABDCABA
样例输出 Copy
5
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
string a,b;
int dp[N][N];
void solve(){
    cin>>a>>b;
    for(int i=1;i<=a.size();i++){
        for(int j=1;j<=b.size();j++){
            if(a[i-1]==b[j-1]){
                dp[i][j]=dp[i-1][j-1]+1;
            }
            else{
                dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            }
        }
    }
    cout<<dp[a.size()][b.size()]<<"\n";
}
int main() {
    cin.tie(0)->sync_with_stdio(false);
    solve();
    return 0;
}

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

题目描述

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

输入

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

输出

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

样例输入 Copy
acdbxx
ccdxx
样例输出 Copy
cdxx
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
int dp[N][N];
void solve(){
    string a,b;
    while(cin>>a>>b){
        memset(dp,0,sizeof dp);
        for(int i=1;i<=a.size();i++){
            for(int j=1;j<=b.size();j++){
                if(a[i-1]==b[j-1]){
                    dp[i][j]=dp[i-1][j-1]+1;
                }
                else{
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
                }
            }
        }
        string s="";
        int i=a.size();
        int j=b.size();
        while(i>0&&j>0){
            if(a[i-1]==b[j-1]){
                s=a[i-1]+s;
                i--;
                j--;
            } 
            else if(dp[i-1][j]>dp[i][j-1]){
                i--;
            } 
            else{
                j--;
            }
        }
        cout<<s<<"\n";
    }
}
int main() {
    cin.tie(0)->sync_with_stdio(false);
    solve();
    return 0;
}

 D:牛牛的字符串

题目描述

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

输入

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

输出

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

样例输入 Copy
abede
abgde
样例输出 Copy
2
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
string a,b;
void solve(){
    while(cin>>a>>b){
        int m=0;
        for(int i=0;i<a.size();i++){
            int n=0;
            for(int j=0;j<b.size();j++){
                if(a[i+n]==b[j]){
                    n++;
                    m=max(m,n);
                }
                else
                    n=0;
            }
        }
        cout<<m<<"\n";
    }
}
int main() {
    cin.tie(0)->sync_with_stdio(false);
    solve();
    return 0;
}

 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 <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
void solve(){
    int n;
    while(cin>>n)
    {
        int s=0,m=0;
        for(int i=1; i<=n; i++)
        {
            int a;
            cin>>a;
            s+=a;
            m=max(m,s);
            if(s<0)
                s=0;
        }
        cout<<m<<"\n";
    }
}
int main() {
    cin.tie(0)->sync_with_stdio(false);
    solve();
    return 0;
}

 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 <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
int a[N];
void solve(){
    int n;
    while(cin>>n){
        for(int i=0;i<n;i++){
            cin>>a[i];
        }
        int sum=-1,ss=-1,s=0,l,r;
        for(int i=0;i<n;i++){
            if(ss<0){
                ss=0;
                s=i;
            }
            ss+=a[i];
            if(sum<ss){
                sum=ss;
                l=s;
                r=i;
            }
        }
        cout<<sum<<" "<<l+1<<" "<<r+1<<"\n";
    }
}
int main() {
    cin.tie(0)->sync_with_stdio(false);
    solve();
    return 0;
}

 G:最短的名字

题目描述

在一个奇怪的村子中,很多人的名字都很长,比如aaaaabbb and abababab

名字这么长,叫全名显然起来很不方便。所以村民之间一般只叫名字的前缀。比如叫'aaaaa'的时候可以只叫'aaa',因为没有第二个人名字的前三个字母是'aaa'。不过你不能叫'a',因为有两个人的名字都以'a'开头。村里的人都很聪明,他们总是用最短的称呼叫人。输入保证村里不会有一个人的名字是另外一个人名字的前缀(作为推论,任意两个人的名字都不会相同)。

如果村里的某个人要叫所有人的名字(包括他自己),他一共会说多少个字母?

输入

输入第一行为数据组数T (T<=10)。每组数据第一行为一个整数n(1<=n<=1000),即村里的人数。以下n行每行为一个人的名字(仅有小写字母组成)。输入保证一个村里所有人名字的长度之和不超过1,000,000。

输出

对于每组数据,输出所有人名字的字母总数。

样例输入 Copy
1
3
aaaaa
bbb
abababab
样例输出 Copy
5
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
void solve(){
    int n;
    cin>>n;
    vector<string> a;
    a.push_back(".");
    for(int i=1;i<=n;i++){
        string ss;
        cin>>ss;
        a.push_back(ss);
    }
    sort(a.begin()+1,a.end());
    a.push_back(".");
    int s=0;
    for(int i=1;i<=n;i++){
        string s1="",s2="",s3="";
        for(int j=0;j<=a[i].size();j++){
            s1+=a[i][j];
            s2+=a[i+1][j];
            s3+=a[i-1][j];
            if(s1==s2||s1==s3){
                continue;
            }
            else{
                s+=j+1;
                break;
            }
        }
    }
    cout<<s<<"\n";
}
int main() {
    cin.tie(0)->sync_with_stdio(false);
    int t;cin>>t;while(t--)
    solve();
    return 0;
}

 H:最大计分

题目描述

小米和小花在玩一个删除数字的游戏。
游戏规则如下:
首先随机写下N个正整数,然后任选一个数字作为起始点,从起始点开始从左往右每次可以删除一个数字,但是必须满足下一个删除的数字要小于上一个删除的数字。每成功删除一个数字计1分。
请问对于给定的N个正整数,一局游戏过后可以得到的最大计分是多少?

输入

单组输入。
第1行输入一个正整数N表示数字的个数(N<=10^3)。
第2行输入N个正整数,两两之间用空格隔开。

输出

对于给定的N个正整数,一局游戏过后可以得到的最大计分值。

样例输入 Copy
6
3 4 3 5 2 1
样例输出 Copy
4
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
int a[N],b[N];
void solve(){
    int n,s=0;
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=1;i<=n;i++)
    {
        b[i]=1;
        for(int j=1;j<i;j++)
            if(a[j]>a[i])
                b[i]=max(b[i],b[j]+1);
        s=max(s,b[i]);
    }
    cout<<s<<"\n";
}
int main() {
    cin.tie(0)->sync_with_stdio(false);
    solve();
    return 0;
}

  • 24
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值