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

A:斜线最大最小值

求如图所示一个上三角矩阵中每一条斜线中的最大元素(L)和最小元素(S)。

输入

每组输入包括两部分,一部分为数字n,表示三角矩阵的行数。
第二部分即为三角矩阵。

输出

每一个对角线输出一行,每行包括Lx=Max, Sx=Min,其中x为斜线序号(序号从1开始),Max为该斜线上的最大值,Min为该斜线上的最小值。

样例输入 Copy
6
1 3 5 7 11 20
0 6 8 2 3 13
0 0 7 4 8 9
0 0 0 18 3 10
0 0 0 0 12 6
0 0 0 0 0 15
样例输出 Copy
L1=18, S1=1
L2=8, S2=3
L3=10, S3=2
L4=9, S4=3
L5=13, S5=11
L6=20, S6=20
#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];
void solve(){
    int n;
    while(cin>>n){
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                cin>>a[i][j];
            }
        }
        int m,mm;
        for(int i=0;i<n;i++){
            m=mm=a[0][i];
            for(int j=1;j<n-i;j++){
                m=max(a[j][i+j],m);
                mm=min(a[j][i+j],mm);
            }
            cout<<'L'<<i+1<<'='<<m<<", S"<<i+1<<'='<<mm<<"\n";
        }
    }
}
int main() {
    cin.tie(0)->sync_with_stdio(false);
    solve();
    return 0;
}

 B:矩阵连乘问题-备忘录法求最优值

题目描述

使用备忘录法求解矩阵连乘问题,输出最少乘法次数。

输入

每组数据包括两行,第一行为数组长度n,第二行为存储矩阵维数的一维数组。

输出

矩阵连乘最优计算次数。

样例输入 Copy
7
30 35 15 5 10 20 25
样例输出 Copy
15125
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
int n;
int a[N];
int b[N][N];
int fun(int i,int j) {
    if(b[i][j]){
        return b[i][j];
    }
    if(i==j){
        return 0;
    }
    else{
        int u=fun(i+1,j)+a[i-1]*a[i]*a[j];
        for(int k=i+1;k<j;k++){
            int t=fun(i,k)+fun(k+1,j)+a[i-1]*a[k]*a[j];
            if(t<u){
                u=t;
            }
        }
        b[i][j]=u;
    }
    return b[i][j];
}
  
void solve(){
    while(cin>>n){
        memset(b,0,sizeof b);
        for(int i=0;i<n;i++){
            cin>>a[i];
        }
        cout<<fun(1,n-1)<<"\n";
    }
}
int main(){
    cin.tie(0)->sync_with_stdio(false);
    solve();
    return 0;
}

 C:矩阵连乘问题-动态规划求最优值

题目描述

使用动态规划算法求解矩阵连乘问题,输出最少乘法次数。

输入

每组数据包括两行,第一行为数组长度n,第二行为存储矩阵维数的一维数组。

输出

矩阵连乘最优计算次数。

样例输入 Copy
7
30 35 15 5 10 20 25
样例输出 Copy
15125
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =1e3 +5;
const int M =1e9 +7;
int n;
int a[N];
int b[N][N];
void solve(){
    while(cin>>n){
        memset(b,0,sizeof b);
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        for(int l=2;l<n;l++){
            for(int i=1;i<n-l+1;i++){
                int j=i+l-1;
                b[i][j]=b[i+1][j]+a[i+1]*a[i]*a[j+1];
                for(int k=i+1;k<j;k++){
                    b[i][j]=min(b[i][k]+b[k+1][j]+a[i]*a[k+1]*a[j+1],b[i][j]);
                }
            }
        }
        cout<<b[1][n-1]<<"\n";
    }
}
int main(){
    cin.tie(0)->sync_with_stdio(false);
    solve();
    return 0;
}

 D:矩阵连乘问题-构造最优解

题目描述

使用动态规划算法求解矩阵连乘问题。

输入

每组数据包括两行,第一行为数组长度n,第二行为存储矩阵维数的一维数组。

输出

矩阵连乘最优计算次序。

样例输入 Copy
7
30 35 15 5 10 20 25
样例输出 Copy
A[2:2] * A[3:3]
A[1:1] * A[2:3]
A[4:4] * A[5:5]
A[4:5] * A[6:6]
A[1:3] * A[4: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];
int b[N][N],s[N][N];
void fun(int l,int r){
    if(s[l][r]){
        fun(l,s[l][r]);
        fun(s[l][r],r);
        cout<<"A["<<l<<":"<<s[l][r]-1<<"] * A["<<s[l][r]<<":"<<r-1<<"]\n";
    }
}
void solve(){
    int n;
    while(cin>>n){
        memset(b,0,sizeof b);
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        for(int l=2;l<n;l++){
            for(int i=1;i<=n-l;i++){
                int j=i+l;
                b[i][j]=inf;
                for(int k=i+1;k<j;k++){
                    int m=b[i][k]+b[k][j]+a[i]*a[k]*a[j];
                    if(b[i][j]>m){
                        b[i][j]=m;
                        s[i][j]=k;
                    }
                }
            }
        }
        fun(1,n);
    }
}
int main(){
    cin.tie(0)->sync_with_stdio(false);
    solve();
    return 0;
}

 E:石子合并问题

题目描述

在一条直线上有n堆石子,每堆有一定的数量,每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数。求把所有石子合并成一堆的最小花费。例如:输入{1,2,3,4,5},输出33。【3+6+9+15=33】

输入

本题应该处理到文件尾,每组输入包括两行,第一行为石子堆的个数n,第二行则为每堆石子的个数。

输出

输出最小花费。

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

 F:X星人的基因

题目描述

X星人的基因由A、B、C、D、E五种不同的结构组合而成。
如果两个性别不同的X星人的基因序列相似度大于50%,按照X星的法律他们是禁止结婚的,等于50%据说还是可以的。
那么基因的相似度怎么计算呢?分别从两个人身上取长度均为N的基因片段,如果它们的最长公共子序列为M,则相似度=M/N。是不是很简单呢?
现在给你两段X星人的基因序列片段,请你判断他们是不是可以结婚?

输入

每一组测试数据包含3行,
第1行数字N表示待比较基因序列片段的长度,N<=10^3。
第2行和第3行为两个长度为N的基因序列片段。
输入0表示结束。

输出

两个X星人是否可以结婚,如果可以输出”Yes“,如果不可以输出”No“。

样例输入 Copy
8
A B C D E A B C
A C C D C B A E
6
A B C D E E
A E D C B B
0
样例输出 Copy
Yes
Yes
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 +5;
const int M = 1e9 +7;
char a[N],b[N];
double dp[N][N];
void solve(){
    double n;
    while(cin>>n&&n){
        for(int i=1;i<=n;i++){
            cin>>a[i]; 
        }
        for(int i=1;i<=n;i++){
            cin>>b[i];
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;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);
                }
            }
        }
        int s=n;
        if(dp[s][s]/n>0.5){
            cout<<"No\n";
        }
        else{
            cout<<"Yes\n";
        }
    }
}
int main() {
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

 G:路径统计

题目描述

小Z住在一个建筑物很整齐的矩形小区的左下角,学校在小区右上角。
小Z和学校之间有M条东西向的道路,有N条南北向的道路。小Z的爸爸每天早上开车送他上学,但是这些道路都是单行线,只能朝北走或者朝东走。
由于道路施工,在某个路口现在有一个警示桩,表示此处暂不能通行。
现在告诉你M和N的值,以及警示桩的位置,请你统计从小Z家到学校有多少条不同的路径(答案对1e9+7取模)?
下图是当M=4,N=4,在从左到右第2条南北方向的道路和从上至下第2条东西方向的道路的交叉口有一个警示桩的示意图。

 

输入

单组输入。
第1行输入两个正整数M和N,分别表示东西向道路和南北向道路的数量,M和N均不超过100,两者之间用英文空格隔开。
第2行输入两个正整数X和Y,表示警示桩的位置,X表示从左到右第X条南北方向的道路,Y表示从上至下第Y条东西方向的道路。(1<=X<=N,1<=Y<=M)

输出

输出从小Z家到学校的不同路径条数(答案对1e9+7取模)。

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

 H:删数问题

题目描述

在一个数列中有N个正整数,现在需要对这个数列进行若干趟删数操作。
每趟删数操作的规则和要求说明如下:
(1) 一趟删数操作包含1次或多次删除操作,每次删除操作均需要删除一个数。
(2) 下一个要删除的数的下标必须大于上一个删除的数。
(3) 下一个要删除的数的值不能大于上一个删除的数。
通过M趟删数操作后正好将数列中所有数字全部都删除完毕。
请问M的最小值为多少?即最少需要多少趟删数操作才可以将数列清空?

输入

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

输出

输出M的最小值,即最少需要多少趟删数操作才能将数列清空。

样例输入 Copy
8
1 5 5 4 3 4 6 2
样例输出 Copy
4
#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<int> a(n);
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    int s=0;
    while(!a.empty()){
        int t=a[0];
        a.erase(a.begin());
        for(int i=0;i<a.size();){
            if(a[i]<=t){
                t=a[i];
                a.erase(a.begin()+i);
            }
            else{
                i++;
            }
        }
        s++;
    }
    cout<<s<<"\n";
}
int main() {
    cin.tie(0)->sync_with_stdio(false);
    solve();
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值