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

问题 A: 斜线最大最小值

[命题人 : 201501010119]

时间限制 : 1.000 sec  内存限制 : 128 MB

提交问题列表

解决: 1041提交量: 2429统计

题目描述

求如图所示一个上三角矩阵中每一条斜线中的最大元素(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;
const int N = 5500;
int main() { 
	int n; 
	while (cin >> n) { 
	vector<vector<int>> a(n, vector<int>(n)); 
	vector<int> L(n), S(n);

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> a[i][j];
        }
    }
    
    for (int r = 1; r <= n; r++) {
        L[r - 1] = a[0][r - 1];
        S[r - 1] = a[0][r - 1];
        
        for (int p = 1; p <= n - r; p++) {
            int q = r - 1 + p;
            if (a[p][q] > L[r - 1]) {
                L[r - 1] = a[p][q];
            }
            if (a[p][q] < S[r - 1]) {
                S[r - 1] = a[p][q];
            }
        }
    }
    
    for (int k = 0; k < n; k++) {
        cout << "L" << k + 1 << "=" << L[k] << ", S" << k + 1 << "=" << S[k] << endl;
    }
}

return 0;
} 

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

[命题人 : 201501010119]

时间限制 : 1.000 sec  内存限制 : 128 MB

提交问题列表

解决: 1169提交量: 1918统计

题目描述

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

输入

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

输出

矩阵连乘最优计算次数。

样例输入 Copy
7
30 35 15 5 10 20 25
样例输出 Copy
15125
#include<bits/stdc++.h>
using namespace std; 
const int maxn = 1e3 + 10; 
int a[maxn], dp[maxn][maxn]; 
int main() {  
	int n; 
	while (~scanf("%d", &n)) {  
		for (int i = 1; i <= n; ++i) 
		scanf("%d", &a[i]); memset(dp, 0, sizeof(dp)); 
		for (int r = 2; r <= n; ++r) {  
			for (int i = 1; i <= n - r + 1; ++i) {  
			int j = i + r - 1; 
			dp[i][j] = dp[i + 1][j] + a[i] * a[i + 1] * a[j + 1]; 
			for (int k = i + 1; k < j; ++k) 
				dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + a[i] * a[k + 1] * a[j + 1]); 
				} 
			} 
			printf("%d\n", dp[1][n - 1]); 
		} 
		return 0; 
} 

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

[命题人 : 201501010119]

时间限制 : 1.000 sec  内存限制 : 128 MB

提交问题列表

解决: 1091提交量: 1940统计

题目描述

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

输入

每组数据包括两行,第一行为数组长度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; 
const int maxn = 1e3 + 10; 
const int inf = 0x3f3f3f3f; 
int a[maxn], dp[maxn][maxn], s[maxn][maxn]; 
void solve(int l, int r) {  
	if (s[l][r])  
	{  
		solve(l, s[l][r]); 
		solve(s[l][r], r);
		 printf("A[%d:%d] * A[%d:%d]\n", l, s[l][r] - 1, s[l][r], r - 1); 
	} 
} 
	
int main() {  
	int n; 
	while (~scanf("%d", &n)) {  
		for (int i = 1; i <= n; ++i) 
		scanf("%d", &a[i]); 
		memset(dp, 0, sizeof(dp)); 
		for (int l = 2; l <= n; ++l) {  
			for (int i = 1; i + l <= n; ++i) {  
			int j = i + l; dp[i][j] = inf; 
			for (int k = i + 1; k < j; ++k) {  
				int x = dp[i][k] + dp[k][j] + a[i] * a[k] * a[j]; 
				if (dp[i][j] > x) {  
					dp[i][j] = x; 
					s[i][j] = k;  
					} 
					} 
			} 
		} 
		solve(1, n);  
	} 
	return 0;
} 	

问题 E: 石子合并问题

[命题人 : 201501010119]

时间限制 : 1.000 sec  内存限制 : 128 MB

提交问题列表

解决: 1008提交量: 2436统计

题目描述

在一条直线上有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;
const int maxn = 250;
const int INF = 0x7fffff;	
int n;					
int S[maxn];			
int sum[maxn][maxn];	
int dp[maxn][maxn];		
int main()
{
	while (~scanf("%d", &n))
	{
		for (int i = 1; i <= n; i++)
			scanf("%d", &S[i]), sum[i][i] = S[i];
		for (int i = 1; i <= n; i++)
			for (int j = i; j <= n; j++)
				dp[i][j] = (i == j ? 0 : INF);
		for (int len = 1; len < n; len++)
		{
			for (int i = 1; i + len <= n; i++)
			{
				int j = i + len;
				for (int k = i; k < j; k++)
				{
					sum[i][j] = sum[i][k] + sum[k + 1][j];
					dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + sum[i][j]);
				}
			}
		}
		cout << dp[1][n] << endl;
		cout << endl;

	}
	return 0;
}

问题 F: X星人的基因

[命题人 : admin]

时间限制 : 1.000 sec  内存限制 : 128 MB

提交问题列表

解决: 712提交量: 2189统计

题目描述

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;
int dp[1050][1050];
const int N = 1e6+10;
char a[N],b[N];
int main(){
	int n;
	while(cin >> n && n != 0){
		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++){
				if(a[i - 1] == b[j - 1]){
					dp[i][j] = dp[i - 1][j - 1] + 1;
				}else {
					dp[i][j] = max(dp[i - 1][j],dp[i][j - 1]);
				}
			}
		}
		double ans = (dp[n][n] - 1) * 1.0 / n;
		cout << ans << endl;
		if(ans <= 0.5){
			cout << "YES" << endl;
		}else cout << "NO" <<endl; 
	}
	return 0;
}

问题 G: 路径统计

[命题人 : admin]

时间限制 : 1.000 sec  内存限制 : 128 MB

提交问题列表

解决: 65提交量: 375统计

题目描述

小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

但是这个只过了27%,不知道为啥,用dfs又超时了

#include<bits/stdc++.h>
using namespace std;
int dp[105][105];
const int mod = 1e9+7;
int main(){
	int n,m,x,y;
	cin >> n >> m >> x >> y;
	for(int i = 1;i <= n;i++)dp[i][m] = 1;
	for(int i = 1;i <= m;i++)dp[1][i] = 1;
	for(int i = 2;i <= n;i++){
		for(int j = m;j >= 1;j--){
			if(i == x && j == y)continue;
			dp[i][j] = (dp[i - 1][j] + dp[i][j + 1]) % mod;
		}
	}
	cout << dp[n][1] << endl;
	return 0;
}
    
//用的dfs方法
#include<bits/stdc++.h>
using namespace std;
bool vis[105][105];
int n,m,x,y;
int ans = 0;
const int mod = 1e9+7;
int a[105][105];
void dfs(int a,int b){
	if(a == 1 && b == m)ans++,ans %= mod;
	if(a < 1 || b < 1 || a > n || b > n || vis[a][b] == true)return;
	dfs(a - 1,b);
	dfs(a,b + 1);
}
int main(){
	cin >> n >> m >> x >> y;
	memset(a,0,sizeof(a));
	vis[x][y] = true;
	dfs(n,1);
	cout << ans << endl;
	return 0;
} 

问题 H: 删数问题

[命题人 : admin]

时间限制 : 1.000 sec  内存限制 : 128 MB

提交问题列表

解决: 44提交量: 131统计

题目描述

在一个数列中有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 <iostream>
#include <vector>
#include <algorithm>

int main() {
        int n;
        std::cin >> n;
        std::vector<int> exp(n);
        for (int i = 0; i < n; i++) {
            std::cin >> exp[i];
        }

        std::vector<int> arr;
        int k = 0;
        for (int i = 0; i < n; i++) {
            int x = exp[i];
            if (k == 0 || x > arr.back()) {
                arr.push_back(x);
                k++;
            } else {
                auto it = std::lower_bound(arr.begin(), arr.end(), x);
                if (it != arr.end()) {
                    *it = x;
                } else {
                    arr.push_back(x);
                    k++;
                }
            }
        }
    std::cout << k << std::endl;

    return 0;
}

  • 17
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值