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

目录

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

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

问题 C: HNUCM的路径统计

问题 D: 滚球游戏

问题 E: X星金币问题

问题 F: XP的矩阵

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

题目描述

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

         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>
提示
路径上的每一步只能从一个数走到下一层中它下面的数或者右下角的数。 
#include<stdio.h>

#include<string.h>

int p[100][100];

int a[100][100];



int max(int a,int b){

return a>=b?a:b;

}



int solve(int i,int j,int n){

if(p[i][j]>=0) return p[i][j];

if(i==n+1) return 0;

return p[i][j]=a[i][j]+max(solve(i+1,j,n),solve(i+1,j+1,n));

}



int main(){

int n;

int i,j;

while(scanf("%d",&n)!=EOF){

for(i=1;i<=n;i++){

for(j=1;j<=i;j++){

scanf("%d",&a[i][j]);

}

}

memset(p,-1,sizeof(p));

solve(1,1,n);

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

}

}

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

题目描述

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

         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>
提示
路径上的每一步只能从一个数走到下一层上和它最近的左边的数或者右边的数。
#include<stdio.h>





int max(int a,int b){

return a>=b?a:b;

}



int solve(int a[100][100],int n){

int i,j;

int dp[100][100];

for(j=1;j<=n;j++){

dp[n][j]=a[n][j];

}

for(int i=n-1;i>=1;i--){

for(int j=1;j<=i;j++){

dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+a[i][j];

}

}

return dp[1][1];

}



int main(){

int a[100][100];

int n;

int i,j;

while(scanf("%d",&n)!=EOF){

for(i=1;i<=n;i++){

for(j=1;j<=i;j++){

scanf("%d",&a[i][j]);

}

}

printf("%d\n",solve(a,n));

}

}

 问题 C: HNUCM的路径统计

题目描述

HNUCM的小明同学特别喜欢下围棋。
一天他盯着围棋棋盘,想到这么一个问题:
有一个矩形棋盘,该棋盘跟围棋棋盘相似,由一个个正方形的小方格组成,小方格一共有n行,每行有m个小方格。如果将一个棋子放在左上角第1行第1列的格子中,每次走一步,但是每步只能朝右或者朝下走一格。
请问从左上角的方格(即第1行第1列)走到右下角(即第n行第m列)的方格,一共有多少条不同的路径?

输入

单组输入。
输入两个正整数n和m,分别表示棋盘的行数和列数,n和m均不超过100,两者之间用1个英文空格隔开。

输出

输出从左上角到右下角满足条件的不同路径数量。答案对1e9+7取模

样例输入 Copy
2 3
样例输出 Copy
3
#include <stdio.h>     
//宏定义问题:C语言中通常使用 MOD 来表示取模操作中的模数
#define MOD 1000000007   
  
int dp[100][100];  
  
int find(int n, int m) {  
    int i, j;  
      
    // 初始化dp数组,虽然这一步不是必须的,因为全局变量会自动初始化为0  
    for (i = 0; i <= n; i++) {    
        for (j = 0; j <= m; j++) {    
            dp[i][j] = 0;    
        }    
    }   
      
    // 初始化边界条件  
    for (i = 1; i <= n; i++) {    
        dp[i][1] = 1;  
    }    
    for (j = 1; j <= m; j++) {    
        dp[1][j] = 1;  
    }    
      
    // 动态规划计算路径数量  
    for (i = 2; i <= n; i++) {   
        for (j = 2; j <= m; j++) {    
            dp[i][j] = (dp[i-1][j] + dp[i][j-1]) % MOD;    
        }    
    }  
      
    return dp[n][m];    
}    
  
int main() {    
    int n, m;   
    scanf("%d%d", &n, &m);  
    printf("%d\n", find(n, m));  
    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<stdio.h>

int max(int a,int b,int c){
	int max=a>=b?a:b;
	return max>=c?max:c;

}

int main(){
	int a[1000][1000];
	int dp[1000][1000];
	int i,j,n;
	while(scanf("%d",&n)!=EOF){
		for(i=1;i<=n;i++){
			for(j=1;j<=2*i-1;j++){
				scanf("%d",&a[i][j]);
			}
		}
		for(j=1;j<=2*n-1;j++){
			dp[n][j]=a[n][j];
		}
		for(i=n-1;i>=1;i--){
			for(j=1;j<=2*i-1;j++){
				dp[i][j]=max(dp[i+1][j],dp[i+1][j+1],dp[i+1][j+2])+a[i][j];
			}
		}
		printf("%d\n",dp[1][1]);
	}
}

问题 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<stdio.h>

int max(int a1,int b,int c){
	int max;
	max=a1>=b?a1:b;
	return max>=c?max:c;

}

int solve(int a[1100][1100],int m,int n){
	int i,j,x;
	for(i=1;i<m;i++){
		for(j=1;j<=n;j++){
			if(j==1){
				a[i+1][j]=a[i][j]>a[i][j+1]?a[i][j]:a[i][j+1]+a[i+1][j];
			}
			else if(j==n){
				a[i+1][j]=a[i][j-1]>a[i][j]?a[i][j-1]:a[i][j]+a[i+1][j];
			}else{
				a[i+1][j]=max(a[i][j-1],a[i][j],a[i][j+1])+a[i+1][j];
			}
		}
	}
	x=a[m][1];
	for(j=1;j<=n;j++){
		if(a[m][j]>x){
			x=a[m][j];
		}
	}
	return x;
}

int main(){
	int a[1100][1100];
	int m,n;
	int i,j;
	while(scanf("%d%d",&m,&n)!=EOF){
		for(i=1;i<=m;i++){
			for(j=1;j<=n;j++){
				scanf("%d",&a[i][j]);
			}
		}
		printf("%d\n",solve(a,m,n));
	}
}

问题 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 <stdio.h>  
  
int min(int a, int b) {  
    return a < b ? a : b;  
}  
  
int solve(int matrix[1000][1000], int m, int n) {  
    int dp[1000][1000]; // 初始化动态规划数组  
    int i, j;  
  
    // 初始化第一行和第一列  
    dp[0][0] = matrix[0][0];  
    for (i = 1; i < m; i++) {  
        dp[i][0] = dp[i - 1][0] + matrix[i][0];  
    }  
    for (j = 1; j < n; j++) {  
        dp[0][j] = dp[0][j - 1] + matrix[0][j];  
    }  
  
    // 填充剩余的dp数组  
    for (i = 1; i < m; i++) {  
        for (j = 1; j < n; j++) {  
            dp[i][j] = matrix[i][j] + min(dp[i - 1][j], dp[i][j - 1]);  
        }  
    }  
  
    // 返回右下角的最小路径和  
    return dp[m - 1][n - 1];  
}  
  
int main() {  
    int T, M, N;  
    int i, j;  
    int matrix[1000][1000];  
  
    // 读取测试用例数  
    scanf("%d", &T);  
    while (T--) {  
        // 读取矩阵的行数和列数  
        scanf("%d %d", &M, &N);  
  
        // 读取矩阵中的元素  
        for (i = 0; i < M; i++) {  
            for (j = 0; j < N; j++) {  
                scanf("%d", &matrix[i][j]);  
            }  
        }  
  
        // 计算并打印最小路径和  
        printf("%d\n", solve(matrix, M, N));  
    }  
  
    return 0;  
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值