PTA 动态规划

这篇具有很好参考价值的文章主要介绍了PTA 动态规划。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

   文章目录

一、函数题

二、编程题


一、编程题

1.租用游艇问题

长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i<j<=n。试设计一个算法,计算出从游艇出租站1 到游艇出租站n所需的最少租金。

输入格式:

第1 行中有1 个正整数n(n<=200),表示有n个游艇出租站。接下来的第1到第n-1 行,第i行表示第i站到第i+1站,第i+2站, ... , 第n站的租金。

输出格式:

输出从游艇出租站1 到游艇出租站n所需的最少租金。

#include<bits/stdc++.h>
using namespace std;
int a[500][500];
int dp[500];
int main()
{
    int n;cin>>n;
    for(int i=1;i<n;i++)
        for(int j=i+1;j<=n;j++)
            cin>>a[i][j];
    memset(dp,0x3f,sizeof dp);
    dp[1]=0;
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
            dp[j]=min(dp[j],dp[i]+a[i][j]);
    cout<<dp[n]<<endl;
}

2.矩阵链相乘问题

矩阵的乘法定义如下:设A是m×p的矩阵,B是p×n的矩阵,则A与B的乘积为m×n的矩阵,记作C=AB,其中,矩阵C中的第i行第j列元素cij​可以表示为:cij​=Σk=1p​aik​×bkj​=ai1​b1j​+ai2​b2j​+⋯+aip​bpj​.

当多个矩阵相乘时,采用不同的计算顺序所需的乘法次数不相同。例如,A是50×10的矩阵,B是10×20的矩阵,C是20×5的矩阵,
计算ABC有两种方式:(AB)C和A(BC),前一种需要15000次乘法计算,后一种则只需3500次。

设A1​,A2​,...,An​为矩阵序列,Ai​是阶为Pi−1​∗Pi​的矩阵(1≤i≤n)。试确定矩阵的乘法顺序,使得计算A1​A2​...An​过程中元素相乘的总次数最少。

输入格式:

每个输入文件为一个测试用例,每个测试用例的第一行给出一个正整数n(1≤n≤100),表示一共有n个矩阵A1​,A2​,...,An​,第二行给出n+1个整数P0​,P1​...Pn​,以空格分隔,其中1≤Pi​≤100(0≤i≤n),第i个矩阵Ai​是阶为Pi−1​∗Pi​的矩阵。

输出格式:

获得上述矩阵的乘积,所需的最少乘法次数

#include<bits/stdc++.h>
using namespace std;
const int N=2000;
int dp[N][N];
int a[N];
int main()
{
    int n;cin>>n;
    memset(dp,0x3f,sizeof dp);
    for(int i=0;i<=n;i++)cin>>a[i],dp[i][i]=0;
    for(int len=2;len<=n;len++)
    {
        for(int l=1;l+len-1<=n;l++)
        {
            int r=l+len-1;
            for(int k=l;k<r;k++)
                dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+a[l-1]*a[k]*a[r]);
        }
    }
    cout<<dp[1][n]<<endl;
}

3.字母表

我们定义一个小写字符串是“按字母表的”,当且仅当它删除掉一些字符后,可以变为”abcdefghijklmnopqrstuvwxyz”。
给定一个长度为n的小写字母字符串,至少插入多少个字符才能使其变成“按字母表的”。

输入格式:

输入第一行为一个整数T(1<=T<=100),代表测试数据的组数,随后T行,每行都是由小写字母'a'-'z'组成的一串字符s (1=<|n|<=50)。

输出格式:

输出为了让s变成“按字母表的”,至少要插入的字符个数,每组输出占一行。

#include<bits/stdc++.h>
using namespace std;
int dp[100];
int main()
{
    int t;cin>>t;
    while(t--)
    {
        string s;cin>>s;int n=s.size();
        int a[100]={0};
        for(int i=0;i<100;i++)dp[i]=1;
        for(int i=0;i<n;i++)a[i+1]=s[i]-'a';
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<i;j++)
            {
                if(a[i]>a[j])dp[i]=max(dp[i],dp[j]+1);
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)ans=max(ans,dp[i]);
        cout<<26-ans<<endl;
    }
}

4.小H分糖果

小H来到一个小学分糖果,小学生们很听话,站成一排等着分糖果,小H将根据每个人的上次考试分数给一定的糖果,规则如下。

  • 每个人都有自己分数ai​,代表上次考试成绩。
  • 每个人都至少有一颗糖。
  • 如果两个人相邻,分数高的一定比分数低的糖果多

然而小H经费有限,他想知道最少需要多少糖果。

输入格式:

输入第一行包括一个整数n(1≤n≤105)。
接下来n行,每行1个整数ai​(1≤ai​≤105)表示站在第i位的人的分数。

输出格式:

输出最少需要多少糖果

#include<bits/stdc++.h>
using namespace std;
const int N=2e5;
int a[N],b[N];
int main()
{
    int n;cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<n;i++)
    {
        if(a[i+1]>a[i])b[i+1]=b[i]+1;
    }
    for(int i=n;i>1;i--)
    {
        if(a[i-1]>a[i])b[i-1]=max(b[i-1],b[i]+1);
    }
    long long ans=0;
    for(int i=1;i<=n;i++)
        ans+=b[i];
    cout<<ans+n<<endl;
}

5.运动会

T公司的员工层级关系可以表示成一棵树,员工X是员工Y的直接领导,则在树中X是Y的父结点。公司拟组织一场运动会,但为了避免尴尬,每个员工都不想与自己的直接领导一起参赛。假定每个员工都对应一个权重(领导的权重不一定比下属大),请你编写程序,邀请若干员工参赛,使得参赛人员的总权重和最大。

输入格式:

第一行一个正整数n,表示公司的员工人数,员工编号为1...n,n不超过3000。
接下来n行,每行1个整数,表示每个员工的权重,值域为[−27,27)。
接下来n-1行,每行为两个空格间隔的整数X和Y,表示Y是X的直接领导。

输出格式:

输出为一个整数,表示参赛员工的最大权重之和。

#include<bits/stdc++.h>
using namespace std;
const int N=3010;
vector<int> a[N];
int root=0,w[N],b[N];
int no[N],yes[N];
void dfs(int u)
{
    if(a[u].empty())
    {
        yes[u]=w[u];
        return;
    }yes[u]=w[u];
    for(int i=0;i<a[u].size();i++)
    {
        dfs(a[u][i]);
        yes[u]+=no[a[u][i]];
        no[u]+=max(yes[a[u][i]],no[a[u][i]]);
    }
}
int main()
{
    int n;cin>>n;
    for(int i=1;i<=n;i++)cin>>w[i];
    for(int i=1;i<n;i++)
    {
        int x,y;cin>>x>>y;
        a[y].push_back(x);b[x]=y;
    }
    for(int i=1;i<=n;i++)
    {
        if(b[i]==0)
            root=i;
    }
    //cout<<root<<endl;
    dfs(root);
    cout<<max(no[root],yes[root]);
}

6.0-1背包

给定n(n<=100)种物品和一个背包。物品i的重量是wi(wi<=100),价值为vi(vi<=100),背包的容量为C(C<=1000)。
应如何选择装入背包中的物品,使得装入背包中物品的总价值最大? 在选择装入背包的物品时,对每种物品i只有两个选择:装入或不装入。不能将物品i装入多次,也不能只装入部分物品i。

输入格式:

共有n+1行输入:
第一行为n值和c值,表示n件物品和背包容量c;
接下来的n行,每行有两个数据,分别表示第i(1≤i≤n)件物品的重量和价值。

输出格式:

输出装入背包中物品的最大总价值。

#include<bits/stdc++.h>
using namespace std;
int w[200],v[200],dp[1010];
int main()
{
    int n,c;cin>>n>>c;
    for(int i=1;i<=n;i++)cin>>w[i]>>v[i];
    for(int i=1;i<=n;i++)
        for(int j=c;j>=w[i];j--)
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
    cout<<dp[c];
}

7.最长公共子序列长度

求两个字符串的最长公共子序列长度。

输入格式:

输入长度≤100的两个字符串。

输出格式:

输出两个字符串的最长公共子序列长度。

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int dp[N][N];
int main()
{
    string a,b;cin>>a>>b;
    a=" "+a;b=" "+b;
    for(int i=1;i<a.size();i++)
    {
        for(int j=1;j<b.size();j++)
        {
            dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            if(a[i]==b[j])dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
        }
    }
    cout<<dp[a.size()-1][b.size()-1];
}

8.jmu-ds-最长公共子串

给出2个字符串,输出2字符串的最长公共子串。

输入格式:

输入2个字符串,不可包含空格。

输出格式:

输出2个字符串的最长公共子串。若没有公共子串,则输出“NULL”

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int dp[N][N];
int main()
{
    string a,b;cin>>a>>b;
    a=" "+a;b=" "+b;
    int len=0,end;
    for(int i=1;i<a.size();i++)
    {
        for(int j=1;j<b.size();j++)
        {
            if(a[i]==b[j])
            {
                dp[i][j]=dp[i-1][j-1]+1;
                if(dp[i][j]>len)
                    len=dp[i][j],end=i;
            }
        }
    }
    if(len)
    {
        for(int i=end-len+1;i<=end;i++)cout<<a[i];
    }
    else cout<<"NULL";
}

9.石子合并

在一个圆形操场的四周摆放 N 堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的 2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出一个算法,计算出将 N 堆石子合并成 1 堆的最小得分和最大得分。

输入格式:

数据的第 1 行是正整数 N ,表示有 N 堆石子。

第 2 行有 N 个整数,第 i 个整数 ai​ 表示第 i 堆石子的个数。

输出格式:

输出共 2 行,第 1 行为最小得分,第 2 行为最大得分。文章来源地址https://www.toymoban.com/news/detail-771683.html

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
int dp1[N][N],dp2[N][N],a[N],s[N];
int main()
{
    int n;cin>>n;
    memset(dp1,0x3f,sizeof dp1);
    memset(dp2,-1,sizeof dp2);
    for(int i=1;i<=n;i++)cin>>a[i],a[i+n]=a[i];
    n=2*n-1;
    for(int i=1;i<=n;i++)
    {
        dp1[i][i]=dp2[i][i]=0;
        s[i]=s[i-1]+a[i];
    }
    for(int len=2;len<=n;len++)
        for(int l=1;l<=n-len+1;l++)
        {
            int r=l+len-1;
            for(int k=l;k<r;k++)
            {
                dp1[l][r]=min(dp1[l][r],dp1[l][k]+dp1[k+1][r]);
                dp2[l][r]=max(dp2[l][r],dp2[l][k]+dp2[k+1][r]);
            }
            dp1[l][r]+=s[r]-s[l-1];
            dp2[l][r]+=s[r]-s[l-1];
        }
    n=(n+1)/2;
    int mi=0x3f3f3f3f,ma=-1;
    for(int i=1;i<=n;i++)
    {
        mi=min(mi,dp1[i][n+i-1]);
        ma=max(ma,dp2[i][n+i-1]);
    }
    cout<<mi<<endl;
    cout<<ma<<endl;
}

到了这里,关于PTA 动态规划的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【学会动态规划】环绕字符串中唯一的子字符串(25)

    目录 动态规划怎么学? 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后: 学习一个算法没有捷径,更何况是学习动态规划, 跟我一起刷动态规划算法题,一起学会动态规划! 题目链接:467. 环绕字符串中唯一的子字

    2024年02月10日
    浏览(38)
  • 【动态规划】【字符串】132.分割回文串 II

    视频算法专题 动态规划汇总 字符串 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。 返回符合要求的 最少分割次数 。 示例 1: 输入:s = “aab” 输出:1 解释:只需一次分割就可将 s 分割成 [“aa”,“b”] 这样两个回文子串。 示例 2: 输入:s = “a”

    2024年02月03日
    浏览(54)
  • 有效的括号字符串(力扣)动态规划、贪心 JAVA

    给你一个只包含三种字符的字符串,支持的字符类型分别是 ‘(’、‘)’ 和 ‘*’。请你检验这个字符串是否为有效字符串,如果是有效字符串返回true 。 有效字符串符合如下规则: 任何左括号 ‘(’ 必须有相应的右括号 ‘)’。 任何右括号 ‘)’ 必须有相应的左括号 ‘(’

    2024年02月14日
    浏览(40)
  • 【算法思考记录】动态规划入门!力扣2606. 找到最大开销的子字符串【Python3、动态规划】

    原题链接 动态规划(Dynamic Programming,简称 DP)是一种通过将原问题分解为相互重叠的子问题并只解决一次的方法来解决问题的算法优化技术。动态规划通常用于优化递归问题,通过存储子问题的解来避免重复计算,从而显著提高算法的效率。 动态规划的基本思想是将原问题

    2024年02月03日
    浏览(44)
  • 【动态规划】【字符串】C++算法:正则表达式匹配

    视频算法专题 动态规划汇总 字符串 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘ ’ 的正则表达式匹配。 ‘.’ 匹配任意单个字符 \\\' ’ 匹配零个或多个前面的那一个元素 所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。 示例 1: 输入:

    2024年02月03日
    浏览(58)
  • 2023-05-27:给你一个只包含小写英文字母的字符串 s 。 每一次 操作 ,你可以选择 s 中两个 相邻 的字符,并将它们交换。 请你返回将 s 变成回文串的 最少操作次数 。 注意 ,输入数据

    2023-05-27:给你一个只包含小写英文字母的字符串 s 。 每一次 操作 ,你可以选择 s 中两个 相邻 的字符,并将它们交换。 请你返回将 s 变成回文串的 最少操作次数 。 注意 ,输入数据会确保 s 一定能变成一个回文串。 输入:s = \\\"letelt\\\"。 输出:2。 答案2023-05-27: 1.定义结构体

    2024年02月06日
    浏览(95)
  • 动态规划16 | ● 583. 两个字符串的删除操作 ● *72. 编辑距离

    https://programmercarl.com/0583.%E4%B8%A4%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E5%88%A0%E9%99%A4%E6%93%8D%E4%BD%9C.html 考点 子序列问题 我的思路 dp[i][j]的含义是,当两个字符串分别取前i和j个元素时,对应的最少相等删除步数是多少 递推公式为,如果两个字符串第i和j个元素恰好相等,则dp值应

    2024年04月22日
    浏览(51)
  • 动态规划 多源路径 字典树 LeetCode2977:转换字符串的最小成本

    动态规划汇总 多源最短路径 字典树 视频算法专题 给你两个下标从 0 开始的字符串 source 和 target ,它们的长度均为 n 并且由 小写 英文字母组成。 另给你两个下标从 0 开始的字符串数组 original 和 changed ,以及一个整数数组 cost ,其中 cost[i] 代表将字符串 original[i] 更改为字符

    2024年02月04日
    浏览(54)
  • 【LeetCode: 97. 交错字符串 | 暴力递归=>记忆化搜索=>动态规划 | 位置对应】

    🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,CSDN-Java领域优质创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文

    2024年02月05日
    浏览(48)
  • 【面试算法——动态规划 21】正则表达式匹配(hard)&& 交错字符串

    链接: 10. 正则表达式匹配 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。 ‘.’ 匹配任意单个字符 ‘*’ 匹配零个或多个前面的那一个元素 所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。 示例 1: 输入:s = “aa”

    2024年02月08日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包