算法复习题解

问题 A: 递归求解

题目描述

请使用递归编写一个程序求如下表达式的计算结果: 
S(1) = 1/2
S(2) = 1/2 + 1/6
S(3) = 1/2 + 1/6 + 1/12
S(4) = 1/2 + 1/6 + 1/12 + 1/20
......
S(n) = 1/2 + 1/6 + 1/12 + 1/20 + 1/30 + ......
输入n (1<n<=1000),输出表达式S(n)的值(精确到小数点后六位)。
请编写一个递归程序实现该功能。

输入

单组输入,输入一个正整数n,1<n<=1000。

输出

输出表达式S(n)的计算结果(精确到小数点后六位)。

样例输入 Copy
2
样例输出 Copy
0.666667
#include<stdio.h>
double font(int n){
	double s=0.0;
	if(n==1)
		return 0.5;
	else
		s=1.000000/(n*(n+1));
	return s+font(n-1);
}
int main(){
	int n;
	scanf("%d",&n);
	printf("%0.6f\n",font(n));
	return 0;
}

问题 B: 挑选奖品

题目描述

X星人参加了一档幸运大抽奖节目,凭借无敌好运气中了一等奖。节目组给他准备了一个奖品箱,这个箱子中一共有M个格子,每个格子中只能放一个奖品。
现在一共有N个不同的奖品供X星人挑选,不同的奖品其价值不一定相等
“贪心的”X星人希望所挑选的奖品的价值和最大,需要你编写一个程序帮他计算出所能得到的最大价值和。

输入

单组输入。
第1行包含两个正整数M和N,分别表示奖品箱中格子的数量和奖品的总数。(1< M<=10^5且1<N<=10^5)
第2行包含N个正整数,分别表示N个奖品的价值,两两之间用空格隔开。

输出

奖品箱中所有奖品的最大价值和。

样例输入 Copy
3 5
1 3 2 6 5
样例输出 Copy
14
#include <stdio.h>
#include <stdlib.h>

// 快速排序函数,降序排列
void quickSort(int arr[], int left, int right) {
    if (left < right) {
        int pivot = arr[left]; // 选择第一个元素作为基准
        int i = left, j = right + 1;
        
        do {
            do { i++; } while (arr[i] > pivot && i <= right);
            do { j--; } while (arr[j] < pivot);
            
            if (i < j) {
                // 交换 arr[i] 和 arr[j]
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        } while (i < j);
        
        // 交换基准元素和 j 处元素
        arr[left] = arr[j];
        arr[j] = pivot;
        
        // 递归排序左右子数组
        quickSort(arr, left, j - 1);
        quickSort(arr, j + 1, right);
    }
}

int main() {
    int M, N;
    scanf("%d %d", &M, &N);

    int values[N];
    for (int i = 0; i < N; ++i) {
        scanf("%d", &values[i]);
    }

    // 使用自定义的快速排序对奖品价值数组进行降序排序
    quickSort(values, 0, N - 1);

    // 计算最大价值和
    long long max_value = 0;
    for (int i = 0; i < M && i < N; ++i) {
        max_value += values[i];
    }

    // 输出结果
    printf("%lld\n", max_value);

    return 0;
}

问题 C: 排列蛋卷

题目描述

刚考完研的TC同学这段时间在家闲得慌,因此他决定学点新手艺。今天他学习的内容是:做蛋卷。
由于是第一次做蛋卷,TC同学做出来蛋卷长短不一。看着这些长度都不一样的蛋卷,TC同学的强迫症又犯了。他希望能够拿出其中部分蛋卷,使得留下来的蛋卷能够按照长度从大到小的次序排列
请问他最少需要拿出多少根蛋卷

输入

单组输入,对于每一组测试数据,第1行N表示蛋卷的总数量(n<=1000)。 
第2行包含N个正整数,分别表示每一根蛋卷的长度。(单位:厘米) 
保证在同一组输入数据中每一根蛋卷的长度均不一样。

输出

输出最少需要拿出的蛋卷数量。

样例输入 Copy
5
15 18 17 11 12
样例输出 Copy
2
#include <stdio.h>

int main() {
    int n;
    while (scanf("%d", &n) == 1) {
        int a[n+1];
        int b[n+1];

        // 读取数组a的值
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }

        // 计算数组b的值
        b[1] = 1;
        for (int i = 2; i <= n; i++) {
            int maxx = 0;
            for (int j = i - 1; j > 0; j--) {
                if (a[j] > a[i] && b[j] > maxx) {
                    maxx = b[j];
                }
            }
            b[i] = maxx + 1;
        }

        // 找出最大不下降子序列的长度
        int maxx2 = b[1];
        for (int i = 2; i <= n; i++) {
            if (b[i] > maxx2) {
                maxx2 = b[i];
            }
        }

        // 输出结果
        int p = n - maxx2;
        printf("%d\n", p);
    }

    return 0;
}

问题 D: 最大收益

题目描述

小X是一位精明的投资人,他每次都能够做出正确的投资判断。
现在有N个项目,每个项目的总投资额和总收益已知,并且每一个项目都允许小X只投资一部分,当然也就只能拿到一部分收益。 
现在小X决定拿出M万元钱来进行投资,请你帮他设计一个算法来计算最大收益和

输入

单组输入,对于每一组数据,第1行包含两个正整数,分别是M和N,其中M<=10^6,N<=100。
接下来N行每行均包含两个正数(不一定是正整数),第1数字表示第N个项目的总投资额(万元),第2个数字表示第N个项目的总收益(万元),两个数字之间用空格隔开。 

输出

小X可以获得的最大收益和(万元,结果四舍五入保留两位小数)。

样例输入 Copy
100 4
50 10 
20 10 
40 10 
50 20
样例输出 Copy
37.50
#include <stdio.h>

#define MAX_ITEMS 105

// 定义物品结构体的索引
typedef struct {
    double w; // weight
    double v; // value
    double vw; // value per unit weight
} Item;

// 冒泡排序函数,根据物品的单位重量价值 vw 进行排序
void bubble_sort(Item arr[], int n) {
    int i, j;
    for (i = 0; i < n-1; i++) {
        for (j = 0; j < n-i-1; j++) {
            if (arr[j].vw < arr[j+1].vw) {
                // 交换 arr[j] 和 arr[j+1]
                Item temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
}

int main() {
    Item items[MAX_ITEMS];
    double M;
    int N;
    
    while (scanf("%lf %d", &M, &N) == 2) {
        // 读取物品的重量和价值,并计算单位重量价值
        for (int i = 0; i < N; i++) {
            scanf("%lf %lf", &items[i].w, &items[i].v);
            items[i].vw = items[i].v / items[i].w;
        }
        
        // 使用冒泡排序函数对物品按照单位重量价值进行降序排序
        bubble_sort(items, N);
        
        double value = 0;
        int i = 0;
        while (i < N && items[i].w <= M) {
            M -= items[i].w;
            value += items[i].v;
            i++;
        }
        
        // 如果还有剩余的M,则用剩余的M购买部分物品
        if (i < N) {
            value += M * items[i].vw;
        }
        
        // 输出结果,保留两位小数
        printf("%.2lf\n", value);
    }
    
    return 0;
}

问题 E: 最小积分

题目描述

Kimi和Sunny决定在线组队玩一个数字游戏,该游戏的规则如下:
(1) 游戏系统随机生成两组正整数,每组N个数字,两组正整数可能不一样;
(2) 每个游戏团队两个人,每个人拿其中一组数字;
(3) 每一轮两个人从自己的那组数字中各取出一个数字,将两个数字相乘作为这一轮的积分,取出的数字不能再重复使用;
(4) 一共玩N轮,将每轮的积分求和,得到一个总积分;
(5) 总积分最小的队伍获胜。
现在需要你编写一个程序帮Kimi和Sunny计算出最小积分和。

输入

单组输入。
第1行输入一个正整数N,N不超过100。
第2行输入N个不超过1000的正整数,表示Kimi拿到的数字,两两之间用空格隔开。
第3行输入N个不超过1000的正整数,表示Sunny拿到的数字,两两之间用空格隔开。

输出

输出最小积分和。

样例输入 Copy
3
3 1 2
4 3 5
样例输出 Copy
22
#include <stdio.h>

// 自定义快速排序函数,降序排列
void qort(int arr[], int left, int right) {
    if (left < right) {
        int pivot = arr[left]; // 选择第一个元素作为基准
        int i = left, j = right + 1;
        
        do {
            do { i++; } while (arr[i] < pivot && i <= right);
            do { j--; } while (arr[j] > pivot);
            
            if (i < j) {
                // 交换 arr[i] 和 arr[j]
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        } while (i < j);
        
        // 交换基准元素和 j 处元素
        arr[left] = arr[j];
        arr[j] = pivot;
        
        // 递归排序左右子数组
        qort(arr, left, j - 1);
        qort(arr, j + 1, right);
    }
}

int main() {
    int N;
    scanf("%d", &N);
    
    int Kimi[N], Sunny[N];
    
    // 读取Kimi拿到的数字
    for (int i = 0; i < N; ++i) {
        scanf("%d", &Kimi[i]);
    }
    
    // 读取Sunny拿到的数字
    for (int i = 0; i < N; ++i) {
        scanf("%d", &Sunny[i]);
    }
    
    // 对两组数字进行升序排序
    qort(Kimi, 0,N-1);
    qort(Sunny, 0,N-1);
    
    // 计算最小积分和
    long long minScore = 0;
    for (int i = 0; i < N; ++i) {
        minScore += (long long)Kimi[i] * Sunny[N - 1 - i];
    }
    
    // 输出最小积分和
    printf("%lld\n", minScore);
    
    return 0;
}

问题 F: 数字迷宫

题目描述

X星有一个很神秘的数字迷宫。这个迷宫是一个由若干小方格区域组成的矩阵,一共包含M行和N列。每一个小方格中都有一个正整数,表示经过这个方格区域所需要的能量值。
现在小Z从最左边的列任选一个方格作为出发点每一次只能向右边、右上或右下方向走一格,但不能走出数字迷宫,最终要到达最右边的列。
请你编写一个程序,输出消耗的总能量最少的那条路线所对应的总能量值(总能量值包含起点方格和终点方格所需能量值)。

输入

单组输入。
第1行输入两个正整数M和N,分别表示数字迷宫的行和列,M和N均不超过1000,两者之间用一个英文空格隔开。
接下来M行,每行包含N个正整数,每个正整数对应经过一个小方格区域所需的能量值,每个能量值均不超过100。同一行的两个正整数之间用一个英文空格隔开。

输出

输出一个正整数,表示总能量最少的那条路线所对应的总能量值。

样例输入 Copy
3 3
3 4 1
6 1 8
3 7 2
样例输出 Copy
5
#include <stdio.h>

#define MAX_M 1000
#define MAX_N 1000
#define INF 1000000000 // 设定一个较大的初始值,表示无穷大

int min(int a, int b) {
    return a < b ? a : b;
}

int main() {
    int M, N;
    int energy[MAX_M][MAX_N];
    int dp[MAX_M][MAX_N];

    // 输入矩阵大小
    scanf("%d %d", &M, &N);

    // 输入能量值矩阵
    for (int i = 0; i < M; ++i) {
        for (int j = 0; j < N; ++j) {
            scanf("%d", &energy[i][j]);
        }
    }

    // 初始化右边界的 dp 值
    for (int i = 0; i < M; ++i) {
        dp[i][N-1] = energy[i][N-1];
    }

    // 动态规划求解最小总能量值
    for (int j = N - 2; j >= 0; --j) {
        for (int i = 0; i < M; ++i) {
            dp[i][j] = energy[i][j] + dp[i][j+1]; // 向右走的情况

            if (i - 1 >= 0) {
                dp[i][j] = min(dp[i][j], energy[i][j] + dp[i-1][j+1]); // 向右上走的情况
            }
            if (i + 1 < M) {
                dp[i][j] = min(dp[i][j], energy[i][j] + dp[i+1][j+1]); // 向右下走的情况
            }
        }
    }

    // 找出最小值,即为答案
    int minEnergy = INF;
    for (int i = 0; i < M; ++i) {
        if (dp[i][0] < minEnergy) {
            minEnergy = dp[i][0];
        }
    }

    printf("%d\n", minEnergy);

    return 0;
}

问题 G: 又见小青蛙跳台阶

题目描述

一个有N级台阶的楼梯,一只小青蛙的初始位置是第0级台阶,它一次可以跳1级台阶,也可以一次跳2级台阶。
现在已知这个楼梯中有两级是坏的,分别是第X级和第Y级,且1<X<Y<N。
请问小青蛙跳到第N级台阶一共有多少种跳法?

输入

单组输入。
输入一行包含三个正整数X,Y和N,N<=20,1<X<Y<N,两两之间用英文空格隔开。

输出

输出小青蛙跳到第N级台阶的跳法数。

样例输入 Copy
2 4 7
样例输出 Copy
2
#include <stdio.h>

int countWays(int X, int Y, int N) {
    int dp[21]; // 由于 N <= 20,定义一个足够大的数组来存储跳法数
    
    // 初始化 dp 数组
    dp[0] = 1; // 初始位置,一种跳法
    dp[1] = 1; // 第1级台阶,一种跳法
    
    for (int i = 2; i <= N; ++i) {
        dp[i] = dp[i-1];
        if (i >= 2) {
            dp[i] += dp[i-2];
        }
        if (i == X || i == Y) {
            dp[i] = 0; // 如果是坏的台阶,跳法数置为0
        }
    }
    
    return dp[N];
}

int main() {
    int X, Y, N;
    scanf("%d %d %d", &X, &Y, &N);
    
    int result = countWays(X, Y, N);
    printf("%d\n", result);
    
    return 0;
}

问题 H: X星礼物问题

题目描述

新的一年又到了,X星最大的企业XYZ公司决定给X星第一小学的小朋友们送一批礼物。
每个小朋友最多只能得到一件礼物(也有可能得不到)。每一件礼物都有一个“喜爱度”,“喜爱度”是一个1-100之间(包含1和100)的数字。
每位小朋友对于礼物的“喜爱度”都有一个预期值,当然有的小朋友预期值高,也有的小朋友预期值低。
XYZ公司希望能够尽量满足每个小朋友的“喜爱度”预期值,送给某位小朋友的礼物的“喜爱度”不能低于这位小朋友的“喜爱度”预期值。
现在一共有M件礼物要发给N个小朋友(N和M均不超过1000),告诉你这M件礼物的“喜爱度”以及N个小朋友的“喜爱度”预期值,请你编写一个程序,统计这M件礼物最多可以满足多少个小朋友的预期值,请输出最多可以满足的人数。

输入

单组输入。
第1行输入两个正整数M和N,分别表示礼物的数量和小朋友的个数,N和M均不超过1000,二者用英文空格隔开。
第2行输入M个正整数,表示M件礼物的“喜爱度”值,每个正整数均不超过100,两两之间用英文空格隔开。
第3行输入N个正整数,表示N个小朋友的“喜爱度”预期值,每个正整数均不超过100,两两之间用英文空格隔开。

输出

输出最多可以满足的小朋友的人数。

样例输入 Copy
3 3
4 1 8
5 2 6
样例输出 Copy
2
#include <stdio.h>

// 快速排序函数,升序排列
void qort(int arr[], int left, int right) {
    if (left < right) {
        int pivot = arr[left]; // 选择第一个元素作为基准
        int i = left, j = right + 1;
        
        do {
            do { i++; } while (arr[i] < pivot && i <= right);
            do { j--; } while (arr[j] > pivot);
            
            if (i < j) {
                // 交换 arr[i] 和 arr[j]
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        } while (i < j);
        
        // 交换基准元素和 j 处元素
        arr[left] = arr[j];
        arr[j] = pivot;
        
        // 递归排序左右子数组
        qort(arr, left, j - 1);
        qort(arr, j + 1, right);
    }
}

// 计算最多可以满足的小朋友的人数
int maxSatisfied(int gifts[], int kids[], int M, int N) {
    // 将礼物和小朋友的喜爱度预期值排序
    qort(gifts, 0,M-1);
    qort(kids, 0,N-1);
    
    int i = 0, j = 0, count = 0;
    
    // 使用贪心算法尽量满足每个小朋友的预期值
    while (i < M && j < N) {
        if (gifts[i] >= kids[j]) { // 如果当前礼物的喜爱度 >= 当前小朋友的预期值
            count++; // 满足了一个小朋友的预期值
            i++; // 继续尝试下一个礼物
            j++; // 下一个小朋友的预期值
        } else {
            i++; // 如果当前礼物的喜爱度 < 当前小朋友的预期值,尝试下一个礼物
        }
    }
    
    return count;
}

int main() {
    int M, N;
    scanf("%d%d", &M, &N);
    
    int gifts[M];
    int kids[N];
    
    // 读取礼物的喜爱度
    for (int i = 0; i < M; i++) {
        scanf("%d", &gifts[i]);
    }
    
    // 读取小朋友的喜爱度预期值
    for (int i = 0; i < N; i++) {
        scanf("%d", &kids[i]);
    }
    
    // 调用函数计算最多可以满足的小朋友的人数
    int result = maxSatisfied(gifts, kids, M, N);
    
    // 输出结果
    printf("%d\n", result);
    
    return 0;
}

问题 I: HNUCM的漂亮石头

题目描述

Kimi在HNUCM的美丽校园中散步,他发现在HNUCM的新月湖旁边有很多漂亮的小石头,他想捡一些小石头回去放到新买的花盆中。
他今天带了一个小塑料袋来装石头,但是该塑料袋能够装的石头的总重量不能超过某一个阈值,要不塑料袋肯定会坏掉,因此Kimi想选一些“高质量”的石头。
已知每一块小石头都有一个重量,Kimi还根据小石头的漂亮程度给每一块小石头打了一个分,我们就把这个打分叫做“漂亮度”吧。
Kimi希望塑料袋中的小石头的“漂亮度”之和达到最大值,现在需要请你编写一个程序帮Kimi计算出可以得到的“漂亮度”之和的最大值。

输入

单组输入。
第1行输入一个正整数n,表示可供选择的小石头总数量。(1<=n<=1000)
第2行输入一个正整数m,表示小塑料袋可以承受的最大重量。(1<=m<=100)
接下来n行,每行输入两个正整数表示某一块小石头的重量和漂亮度,第1个正整数表示重量,第2个正整数表示漂亮度,两者之间用英文空格隔开。

输出

输出小塑料袋中装入的石头的“漂亮度”之和的最大值。

样例输入 Copy
5
10
3 8
2 10
5 13
4 30
3 6
样例输出 Copy
48
#include<stdio.h>
int a[1005][2];
int dp[105];
int max(int a,int b){
	return a>b?a:b;
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++){
        scanf("%d%d",&a[i][0],&a[i][1]);
    }
    for(int i=0;i<n;i++){
        for(int j=m;j>=a[i][0];j--){
            dp[j]=max(dp[j],dp[j-a[i][0]]+a[i][1]);
        }
    }
    printf("%d\n",dp[m]);
    return 0;
}

问题 J: HNUCM的批改作文

题目描述

HNUCM的小王老师给同学们布置了一道小作文题,要求所有同学同时提交并现场批改。
批改完的同学即可以下课,否则就需要等待老师把自己的作文批改完才能够下课。
交小作文的时间到了,N个同学同时把作文提交给了小王老师,小王老师根据大家写的字数估算了一下批改时间(单位:分钟),现在请你编写一个程序帮助小王老师做一个决策,使得所有同学等待作文批改的平均时间最少,请输出最少平均等待时间(单位:分钟)。

输入

单组输入。
第1行输入一个不超过100的正整数N。
第2行输入N个不超过20的正整数,每一个正整数对应一个同学的作文批改时间(单位:分钟),两个正整数之间用英文空格分隔。

输出

输出所有同学的作文都批改完时的最少平均等待时间(单位:分钟),结果四舍五入保留两位小数。

样例输入 Copy
3
10 5 20
样例输出 Copy
18.33
#include <stdio.h>

// 快速排序函数,升序排列
void qort(int arr[], int left, int right) {
    if (left < right) {
        int pivot = arr[left]; // 选择第一个元素作为基准
        int i = left, j = right + 1;
        
        do {
            do { i++; } while (arr[i] < pivot && i <= right);
            do { j--; } while (arr[j] > pivot);
            
            if (i < j) {
                // 交换 arr[i] 和 arr[j]
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        } while (i < j);
        
        // 交换基准元素和 j 处元素
        arr[left] = arr[j];
        arr[j] = pivot;
        
        // 递归排序左右子数组
        qort(arr, left, j - 1);
        qort(arr, j + 1, right);
    }
}


int main() {
    int N;
    scanf("%d", &N);
    
    int times[N];
    
    // 读取每个同学的作文批改时间
    for (int i = 0; i < N; ++i) {
        scanf("%d", &times[i]);
    }
    
    // 对作文批改时间进行排序
    qort(times, 0,N-1);
    
    // 计算最少平均等待时间
    double total = 0.0;
    double current = 0.0;
    
    for (int i = 0; i < N; ++i) {
        current += times[i]; // 累加当前同学的等待时间
        total += current; // 累加到总等待时间中
    }
    
    // 计算平均等待时间
    double average = total / N;
    
    // 输出结果,保留两位小数
    printf("%.2f\n", average);
    
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值