2023年秋季学期《算法分析与设计》练习9 OJ-1397 算法分析与设计练习9,使用python、C语言

数字三角形之动态规划法

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

 

         7

       3   8

     8   1   2

   2   7   4   4

4    5   2   6   5

 

输入
多组样例输入,每组第一行输入三角形的层数n,接下来n行输入三角形。
输出
输出最佳路径上的数字之和。
样例输入 Copy
<span style="background-color:#ffffff"><span style="color:#333333"><span style="color:#333333"><span style="background-color:#f5f5f5">2
1
1 2
3
1
1 2
1 2 3</span></span></span></span>
样例输出 Copy
<span style="background-color:#ffffff"><span style="color:#333333"><span style="color:#333333"><span style="background-color:#f5f5f5">3
6</span></span></span></span>
提示
路径上的每一步只能从一个数走到下一层上和它最近的左边的数或者右边的数。
a = [[0] * 100 for _ in range(100)]
dp = [[0] * 100 for _ in range(100)]

def solve(n, i, j):
    if dp[i][j] != 0:
        return dp[i][j]
    else:
        if i == n:
            return a[i][j]
        else:
            dp[i][j] = a[i][j] + max(solve(n, i+1, j), solve(n, i+1, j+1))
            return dp[i][j]

while True:
    try:
        n = int(input())
        
        for i in range(1, n+1):
            nums = list(map(int, input().split()))
            for j in range(1, i+1):
                dp[i][j] = 0
                a[i][j] = nums[j-1]
        
        print(solve(n, 1, 1))
    except:
        break

 滚球游戏

题目描述

某滚球游戏规则如下:球从入口处(第一层)开始向下滚动,每次可向下滚动一层,直到滚至最下面一层为止。球每次可滚至左下、下方或右下三个方格中的任意一个,每个方格都有一个得分,如样例所示。第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 <stdio.h>

int max_da(int i, int j, int t) {
    int a = (i > j) ? i : j;
    int b = (j > t) ? j : t;
    int c = (a > b) ? a : b;
    return c;
}

int main() {
    while (1) {
        int n;
        if (scanf("%d", &n) == EOF) {
            break;
        }
        
        int a[101][201] = {0};
        int p[101][201] = {0};
        
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= 2 * i - 1; j++) {
                scanf("%d", &a[i][j]);
            }
        }

        for (int j = 1; j <= 2 * n - 1; j++) {
            p[n][j] = a[n][j];
        }

        for (int i = n - 1; i >= 1; i--) {
            for (int j = 1; j <= 2 * i - 1; j++) {
                p[i][j] = a[i][j] + max_da(p[i + 1][j], p[i + 1][j + 1], p[i + 1][j + 2]);
            }
        }

        printf("%d\n", p[1][1]);
    }

    return 0;
}

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

题目描述

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

输入

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

输出

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

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

int c[101][101];

int LSC(char x[], char y[], int m, int n) {
    if (m == 0 || n == 0) {
        return 0;
    }
    if (c[m][n] != 0) {
        return c[m][n];
    } else {
        if (x[m - 1] == y[n - 1]) {
            c[m][n] = LSC(x, y, m - 1, n - 1) + 1;
        } else {
            int left = LSC(x, y, m - 1, n);
            int up = LSC(x, y, m, n - 1);
            c[m][n] = (left > up) ? left : up;
        }
        return c[m][n];
    }
}

int main() {
    char x[101], y[101];
    while (1) {
        if (scanf("%s", x) == EOF) {
            break;
        }
        scanf("%s", y);
        int m = strlen(x);
        int n = strlen(y);
        memset(c, 0, sizeof(c));// 将二维数组 c 的所有元素初始化为0 
        printf("%d\n\n", LSC(x, y, m, n));
    }
    return 0;
}

斜线最大最小值

题目描述

求如图所示一个上三角矩阵中每一条斜线中的最大元素(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

def slove(n, a):
    for r in range(n):
        max = int(a[0][r])
        min = int(a[0][r])
        for i in range(0, n - r):
            j = int(r + i)
            if max < a[i][j]:
                max = a[i][j]
            if min > a[i][j]:
                min = a[i][j]
        print("L%d=%d, S%d=%d" % (r+1, max, r+1, min))

def in_data(n):
    a = []
    for i in range(n):
        a.append(list(map(int, input().split())))
    return a

while True:
    n = int(input())
    a = in_data(n)
    slove(n, a)

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

题目描述

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

输入

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

输出

矩阵连乘最优计算次数。

样例输入 Copy
7
30 35 15 5 10 20 25
样例输出 Copy
15125
def slove(x, y):
    for r in range(2, y):
        for i in range(1, y-r+1):
            j = i+r-1
            dp[i][j] = dp[i+1][j]+p[i-1]*p[i]*p[j]
            for k in range(i+1, j):
                dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j]+p[i-1]*p[k]*p[j])
    return dp[x][y-1]

while True:
    n = int(input())
    p = [int(i) for i in input().split()]
    dp = [[0] * n for _ in range(n)]
    print(slove(1, n))

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

题目描述

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

输入

每组数据包括两行,第一行为数组长度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]
def slove(x, y):
    for r in range(2, y):
        for i in range(1, y-r+1):
            j = i+r-1
            dp[i][j] = dp[i+1][j]+p[i-1]*p[i]*p[j]
            s[i][j] = i
            for k in range(i+1, j):
                t = dp[i][k]+dp[k+1][j]+p[i-1]*p[k]*p[j]
                if t < dp[i][j]:
                    dp[i][j] = t
                    s[i][j] = k

def tr(i, j):
    if i == j:
        return
    tr(i, s[i][j])
    tr(s[i][j]+1, j)
    m = s[i][j]+1
    print(f"A[{i}:{s[i][j]}] * A[{m}:{j}]")

def in_data(n):
    p = [int(i) for i in input().split()]
    return p

while True:
    n = int(input())
    p = in_data(n)
    dp = [[0] * n for _ in range(n)]
    s = [[0] * n for _ in range(n)]
    slove(1, n)
    tr(1, n-1)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值