算法回忆录(1)

1.编程求1*2*3*4*……*n的末尾有多少个0。

#include <stdio.h>

// 计算 n! 中末尾的0的个数
int count_zeros_in_factorial(int n) {
    int count = 0;
    for (int i = 5; n / i >= 1; i *= 5) {
        count += n / i;
    }
    return count;
}

int main() {
    int n;
    printf("请输入一个整数 n:");
    scanf("%d", &n);
    
    int zeros_count = count_zeros_in_factorial(n);
    printf("%d! 的末尾有 %d 个0\n", n, zeros_count);
    
    return 0;
}

解释和步骤:

  1. 函数 count_zeros_in_factorial: 这个函数用于计算 n! 中末尾的0的个数。通过一个循环,从 i=5 开始,每次乘以5,累加 n / i 的值到 count 中,直到 n / i 的值小于1为止。这样就计算了所有能被 5,25,125,…整除的数的个数。

  2. 主函数 main: 在 main 函数中,首先获取用户输入的整数 n,然后调用 count_zeros_in_factorial 函数计算 n! 的末尾0的个数,并输出结果。

运行结果: 

 

2.请输入一个50至100之间的整数n,求解n!。

#include <stdio.h>

#define MAX_DIGITS 500 // 定义最大位数为500,足以容纳100的阶乘

// 函数声明:计算大整数阶乘
void factorial(int n, int result[], int *result_size);

// 打印大整数数组
void printBigNumber(int result[], int result_size) {
    for (int i = result_size - 1; i >= 0; i--) {
        printf("%d", result[i]);
    }
    printf("\n");
}

// 计算大整数阶乘
void factorial(int n, int result[], int *result_size) {
    result[0] = 1; // 初始结果为1
    *result_size = 1; // 初始结果位数为1
    
    // 计算 n!,从2开始乘到n
    for (int i = 2; i <= n; i++) {
        int carry = 0; // 进位
        for (int j = 0; j < *result_size; j++) {
            int product = result[j] * i + carry;
            result[j] = product % 10; // 取个位数作为当前位
            carry = product / 10; // 进位数
        }
        
        // 处理剩余的进位
        while (carry > 0) {
            result[*result_size] = carry % 10;
            carry = carry / 10;
            (*result_size)++;
        }
    }
}

int main() {
    int n;
    printf("请输入一个50至100之间的整数 n:");
    scanf("%d", &n);
    
    if (n < 50 || n > 100) {
        printf("输入的整数不在50至100之间。\n");
        return 1;
    }
    
    // 创建数组来存储结果
    int result[MAX_DIGITS];
    int result_size; // 存储结果的位数
    
    // 计算阶乘
    factorial(n, result, &result_size);
    
    // 输出结果
    printf("%d! = ", n);
    printBigNumber(result, result_size);
    
    return 0;
}

解释和步骤:

  1. 数组和常量定义

    • MAX_DIGITS 定义了数组的最大长度,足够存储50至100之间任意整数的阶乘结果。
  2. 函数 factorial

    • 接受一个整数 n 和一个数组 result 来存储阶乘的结果,以及一个指针 result_size 来记录结果的位数。
    • 初始时,将结果设置为1,并且结果位数为1。
    • 使用两层循环来模拟手工乘法的过程,每次将当前乘积的个位数存入数组中,并记录进位数。
    • 每次乘完一轮,检查是否有剩余的进位需要处理,直到没有进位为止。
  3. 主函数 main

    • 提示用户输入一个50至100之间的整数 n
    • 检查输入是否在有效范围内,如果不在范围内则输出错误信息并结束程序。
    • 创建一个足够大的数组 result 来存储阶乘的结果。
    • 调用 factorial 函数计算阶乘,并将结果存储在 result 数组中。
    • 调用 printBigNumber 函数打印计算出的阶乘结果。

运行结果: 

3. 有A、B、C、D、E 5个人为某次竞赛的前五名,他们在名次公布前猜名次。

A说:B得第三名,C得第五名。

B说:D得第二名,E得第四名。

C说:B得第一名,E得第四名。

D说:C得第一名,B得第二名。

E说:D得第二名,A得第三名。

结果每个人都猜对了一半,实际名次是什么?

#include <stdio.h>

int main() {
    int A, B, C, D, E; // A, B, C, D, E 分别代表ABCDE五人的名次
    
    // 穷举ABCDE的排名,满足每个人猜对一半的条件
    for (A = 1; A <= 5; ++A) {
        for (B = 1; B <= 5; ++B) {
            if (B == A) continue; // B不能和A同名次
            for (C = 1; C <= 5; ++C) {
                if (C == A || C == B) continue; // C不能和A或B同名次
                for (D = 1; D <= 5; ++D) {
                    if (D == A || D == B || D == C) continue; // D不能和A、B或C同名次
                    for (E = 1; E <= 5; ++E) {
                        if (E == A || E == B || E == C || E == D) continue; // E不能和A、B、C或D同名次
                        
                        // 检查每个人的猜测是否正确
                        int correct_count = 0;
                        
                        if (B == 3 && C == 5) correct_count++; // A猜测
                        if (D == 2 && E == 4) correct_count++; // B猜测
                        if (B == 1 && E == 4) correct_count++; // C猜测
                        if (C == 1 && B == 2) correct_count++; // D猜测
                        if (D == 2 && A == 3) correct_count++; // E猜测
                        
                        // 判断是否满足每个人猜对一半的条件
                        if (correct_count == 2) {
                            printf("实际名次为:A=%d, B=%d, C=%d, D=%d, E=%d\n", A, B, C, D, E);
                            return 0;
                        }
                    }
                }
            }
        }
    }
    
    return 0;
}

 解释和步骤:

  1. 穷举法:通过嵌套的循环遍历ABCDE五人可能的排名组合,从1到5,确保每个人的名次都不同。

  2. 条件检查:在每个排名组合中,检查每个人的猜测是否正确,根据题目提供的猜测条件进行判断。

  3. 正确答案判定:当找到满足每个人猜对一半条件的排名组合时,即输出实际名次。

运行结果:  

4.百马百担问题:有100匹马,驮100担货。大马驮3担,中马驮2担,两匹小马驮1担,问大、中、小马各多少?

#include <stdio.h>

int main() {
    int x, y, z; // x, y, z 分别表示大马、中马、小马的数量
    
    // 穷举大马、中马、小马的数量,满足总数为100匹马,总载重为100担
    for (x = 0; x <= 100; ++x) {
        for (y = 0; y <= 100 - x; ++y) {
            z = (100 - 3*x - 2*y) * 2; // 计算小马的数量
            
            // 检查是否满足每种马的驮载条件
            if (z >= 0 && z % 2 == 0&&x+y+z==100) {
                printf("大马:%d 匹,中马:%d 匹,小马:%d 匹\n", x, y, z);
            }
        }
    }
    
    return 0;
}

 解释和步骤:

  1. 穷举法:通过嵌套的循环遍历大、中、小马的数量可能组合,确保它们的总数为100匹马,同时总载重为100担货物。

  2. 条件检查:在每个马匹数量组合中,计算总载重是否为100担。如果满足条件,则输出对应的大马、中马、小马的数量。

  3. 输出结果:程序将打印所有满足条件的组合,即大、中、小马各自的数量,使得总数为100匹马,总载重为100担货物。

运行结果:  

5. 输入整数N、K以及长度为N的无序序列,找到第K小数并输出。第一行输入N和K,第二行输入长度为N的整数数组。

#include <stdio.h>

// 交换函数,用于交换数组中两个元素的位置
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// 分割函数,用于将数组按照基准数分成两部分,并返回基准数的位置
int partition(int arr[], int left, int right) {
    int pivot = arr[right]; // 选择最右边的元素作为基准数
    int i = left - 1; // i指向小于基准数的区域的最后一个元素
    
    for (int j = left; j < right; ++j) {
        if (arr[j] <= pivot) {
            i++;
            swap(&arr[i], &arr[j]);
        }
    }
    
    swap(&arr[i + 1], &arr[right]); // 将基准数放到正确的位置上
    return i + 1; // 返回基准数的位置
}

// 寻找第K小的数的函数
int findKthSmallest(int arr[], int left, int right, int k) {
    if (k > 0 && k <= right - left + 1) {
        int pivotIndex = partition(arr, left, right);
        
        if (pivotIndex - left == k - 1)
            return arr[pivotIndex];
        
        if (pivotIndex - left > k - 1)
            return findKthSmallest(arr, left, pivotIndex - 1, k);
        
        return findKthSmallest(arr, pivotIndex + 1, right, k - (pivotIndex - left + 1));
    }
    
    return -1; // 如果k超出数组长度的范围,返回-1表示未找到
}

int main() {
    int N, K;
    printf("请输入整数 N 和 K:");
    scanf("%d %d", &N, &K);
    
    int arr[N];
    printf("请输入长度为 N 的整数数组:");
    for (int i = 0; i < N; ++i) {
        scanf("%d", &arr[i]);
    }
    
    int result = findKthSmallest(arr, 0, N - 1, K);
    if (result != -1)
        printf("第 %d 小的数是:%d\n", K, result);
    else
        printf("输入的 K 超出数组长度的范围。\n");
    
    return 0;
}

解释和步骤:

  1. swap函数:用于交换数组中两个元素的位置。

  2. partition函数:实现分割函数,选择最右边的元素作为基准数(pivot),将数组分成两部分,小于等于基准数的放在左边,大于基准数的放在右边,并返回基准数的位置。

  3. findKthSmallest函数:递归地寻找第K小的数。在每次调用中,根据partition函数返回的基准数的位置,判断应该继续在左侧还是右侧进行搜索,直到找到第K小的数为止。

  4. 主函数main

    • 输入N和K。
    • 输入长度为N的整数数组。
    • 调用findKthSmallest函数找到第K小的数,并输出结果。

运行结果:  

 结语  

最暗的夜

才会看见最美的星光

人生亦是如此

!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT 青年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值