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

 A:数字三角形之备忘录法

题目描述

如下图所示的数字三角形,从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。编写一个程序求出最佳路径上的数字之和。 【使用备忘录法实现】
 

         7

       3   8

     8   1   2

   2   7   4   4

4    5   2   6   5

 

输入

多组样例输入,每组第一行输入三角形的层数n,接下来n行输入三角形。

输出

输出最佳路径上的数字之和。

样例输入 Copy

2
1
1 2
3
1
1 2
1 2 3

样例输出 Copy

3
6

提示

路径上的每一步只能从一个数走到下一层中它下面的数或者右下角的数。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
int n;
int p[N][N],a[N][N];
int fun(int i,int j){
    if(i==n+1){
        return 0;
    }
    if(p[i][j]==-1){
        p[i][j]=max(fun(i+1,j),fun(i+1,j+1))+a[i][j];
    }
    return p[i][j];
}
void solve(){
    while(cin>>n){
        memset(p,-1,sizeof p);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=i;j++)
                cin>>a[i][j];
        cout<<fun(1,1)<<'\n';
    }
}
int main() {
    cin.tie(0)->sync_with_stdio(false);
    solve();
    return 0;
}

B:数字三角形之动态规划法

题目描述
如下图所示的数字三角形,从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。编写一个程序求出最佳路径上的数字之和。 【使用动态规划法实现】

 

         7

       3   8

     8   1   2

   2   7   4   4

4    5   2   6   5

 

输入
多组样例输入,每组第一行输入三角形的层数n,接下来n行输入三角形。
输出
输出最佳路径上的数字之和。
样例输入 Copy
2
1
1 2
3
1
1 2
1 2 3
样例输出 Copy
3
6
提示
路径上的每一步只能从一个数走到下一层上和它最近的左边的数或者右边的数。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
int a[N][N];
int dp[N][N];
void solve(){
    int r;
    while(cin>>r){
        for(int i=1;i<=r;i++){
            for(int j=1;j<=i;j++){
                cin>>a[i][j];
            }
        }
        dp[1][1]=a[1][1];
        for(int i=1;i<=r;i++){
            for(int j=1;j<=i;j++){
                dp[i][j]=max(dp[i-1][j-1],dp[i-1][j])+a[i][j];
            }
        }
        int s=0;
        for(int i=1;i<=r;i++){
            s=max(s,dp[r][i]);
        }
        cout<<s<<"\n";
    }
}
int main() {
    ios::sync_with_stdio(0);cin.tie(0);
    solve();
    return 0;
}

 C:HNUCM的路径统计(暂无题面)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e4 + 5;
const ll M= 1e9 + 7;
int dp[105][105];
void solve(){
    int n,m;
    cin>>n>>m;
    dp[0][0]=1;
    for(int i=1;i<n;i++){
        dp[i][0]=1;
    }
    for(int j=1;j<m;j++){
        dp[0][j]=1; 
    }
    for(int i=1;i<n;i++){
        for(int j=1;j<m;j++){
            dp[i][j]=(dp[i-1][j]+dp[i][j-1])%M;
        }
    }
    cout<<dp[n-1][m-1]%M<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

 D:滚球游戏

题目描述

某滚球游戏规则如下:球从入口处(第一层)开始向下滚动,每次可向下滚动一层,直到滚至最下面一层为止。球每次可滚至左下、下方或右下三个方格中的任意一个,每个方格都有一个得分,如样例所示。第1层有1个方格,第2层有3个方格,……,以此类推,第n层有2*n-1个方格。设计一个算法,使得球从入口滚至最下面一层的总得分和最大。

输入

对于每个样例,第1行的正整数n表示数字三角形的行数。(n<=100)
接下来n行包含一个数字三角形,每一行包含2*n-1个方格,对应有2*n-1个表示得分的正整数(不超过10^5),每两个数字之间用空格隔开。
每两组样例之间有一个空行。

输出

球从入口(第一层)滚至最下面一层的最大得分和。

样例输入 Copy
2
  3
2 1 3

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

 E:X星金币问题

题目描述

小X在挑战一个收集金币的游戏。
已知有一个由若干小方格组成的矩形区域,一共包含M行和N列。每一个小方格中都有一个正整数,表示该方格中的金币数目。
现在小X从最上面的行(第1行)任选一个方格作为出发点,每一次只能向正下方、左下方或者右下方走一格,但不能走出矩形区域,最终要到达矩形区域的最后一行。
小X每走一格就会收集该方格中的全部金币。
请你编写一个程序,输出小X最多可以收集多少枚金币?(包含起始方格和结束方格中所包含的金币)。

输入

单组输入。
第1行输入两个正整数M和N,分别表示矩形区域的行和列,M和N均不超过1000,两者之间用一个英文空格隔开。
接下来M行,每行包含N个正整数,每个正整数表示对应方格中的金币数,每个方格中的金币数均不超过100。同一行的两个正整数之间用一个英文空格隔开。

输出

输出一个正整数,表示小X从第1行到最后一行能够收集到的最多金币数。

样例输入 Copy
3 3
2 1 1
8 5 9
2 1 10
样例输出 Copy
20
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 5;
int a[N][N];
int dp[N][N];
void solve(){
    int m,n;
    cin>>m>>n;
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            cin>>a[i][j];
        }
    }
    for(int j=0;j<n;j++){
        dp[0][j]=a[0][j];
    }
    for(int i=1;i<m;i++){
        for(int j=0;j<n;j++){
            dp[i][j]=dp[i-1][j];
            if(j>0){
                dp[i][j]=max(dp[i][j],dp[i-1][j-1]);
            }
            if(j<n-1){
                dp[i][j]=max(dp[i][j],dp[i-1][j+1]);
            }
            dp[i][j]+=a[i][j];
        }
    }
    int mm=dp[m-1][0];
    for(int j=1;j<n;j++){
        mm=max(mm,dp[m-1][j]);
    }
    cout<<mm<<"\n";
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

 F:XP的矩阵

题目描述

XP学长觉得矩阵很美,虽然他也不知道美在哪里,因此,他决定挖掘一下矩阵的美。现在给定一个m行n列的矩阵,从左上角开始每次只能向右或者向下移动,最后到达右下角的位置,将路径上的所有数字累加起来作为这条路径的路径和。XP学长决定编写一个程序来求所有路径和中的最小路径和。例如,下面矩阵中的路径1-3-1-0-6-1-0是所有路径中路径和最小的,返回结果是12。
1 3 5 9
8 1 3 4
5 0 6 1
8 8 4 0
 

输入

输入包含多组测试用例,第一行输入一个T表示测试数据组数,(1<=T<=15)
接下来有T组数据,每组先输入两个整数M,N接下来输入M*N的矩阵(1<=N,M<=1000),且最终结果在int范围内。

输出

输出路径和的最小值。

样例输入 Copy
1
4 4
1 3 5 9
8 1 3 4
5 0 6 1
8 8 4 0
样例输出 Copy
12
#include<iostream>
using namespace std;
int a[1024][1024];
int dp[1024][1024];
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t,m,n,i,j;
    cin >> t;
    while(t>0) {
        cin >> m>>n;
        for(i=0; i<m; i++) for(j=0; j<n; j++) cin >> a[i][j];
        dp[0][0] = a[0][0];
        for(i=1; i<m; i++) dp[i][0] = dp[i-1][0] + a[i][0];
        for(j=1; j<n; j++) dp[0][j] = dp[0][j-1] + a[0][j];
        for(i=1; i<m; i++) for(j=1; j<n; j++) dp[i][j] = (dp[i-1][j]<dp[i][j-1]?dp[i-1][j]:dp[i][j-1]) + a[i][j];
        cout << dp[m-1][n-1] << "\n";
        t--;
    }
    return 0;
}

 G:最长重复AB串

题目描述

X星人最近发明了一种暗语,在这套暗语中只包含两个字符A和B。
暗语中的“AB”串据说表示心情好,“AB”串连续重复次数越多表示X星人越开心。
现在给你一串X星人的暗语,请计算最长连续重复AB串的长度。
例如暗语“ABBABABABBAAB”中最长连续重复AB串的长度为6,即第4个到第9个字符。

输入

每组输入数据占1行,包含一串X星人的暗语,其长度不超过100000个字符。

输出

每组输出占1行,包含一个整数,表示最长连续重复AB串的长度。

样例输入 Copy
ABBABABABBAAB
样例输出 Copy
6
#include <iostream>
#include <string>
using namespace std;
int fun(string s)
{
    int m = 0,a = 0;
    int n=s.size();
    if(n==1)
        return m;
    else
    {
        for (int i = 0; i < n; i++)
            if (s[i] == 'A' && s[i+1] == 'B')
            {
                a += 2;
                i++;
                m = max(m, a);
            }
            else
                a = 0;
        return m;
    }
}
int main() {
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    string s;
    while(cin >> s)
        cout << fun(s) << "\n";
    return 0;
}

 H:完美序列

题目描述

已知一个长度为l的序列:b1,b2,b3,…,bl (1<=b1<=b2<=b3<=…<=bl<=n)。若这个序列满足每个元素是它后续元素的因子,换句话说就是对于任意的i (2<=i<=l)都满足bi%bi-1=0 (其中“%”代表求余),则称这个序列是完美的。你的任务是对于给定的n和l,计算出一共有多少序列是完美序列。由于答案很大,所有输出答案对1000000007取余后的结果。

输入

输入的第一行为一个正整数T (T<=1000),代表一共有T组测试数据。

每组测试数据包含两个正整数n,l (1<=n, l<=2000),分别代表序列中元素值上限和序列的长度。

输出

对于每组测试数据,输出一行包含一个整数,代表答案对1000000007取余后的结果。

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

 

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值