程设期末考题解

/*
1. 计算二项式系数(15’)
给定 n, m <= 40,计算二项式系数 C(n, m) = n!/(m!(n-m)!)。保证结果在整型(int)范围内。
int binomial_coefficient(int n, int m){
    //write your code here
}
*/
#include <stdio.h>
#include <stdlib.h>

int min(int a, int b) {
    int m = a < b ? a : b;
    return m;
}
int binomial_coefficient_0(int n, int m) { // 按照阶乘展开公式直接计算
    long double ans = 1;
    for (int i = 0; i < m; i++) {
        ans = ans * (n - i);
        ans = ans / (m - i);
    }            // 乘以最大数后,立即除以最大数,缓解溢出风险
    return ans; // 隐式强制转换
}

int binomial_coefficient_1(int n, int m) { // 按照二项式公式递归计算,调用函数时间开销大
    if (m == 0 || n == m)
        return 1; // C(n, 0) == c(n, n) == 1
    return binomial_coefficient_1(n - 1, m - 1) + binomial_coefficient_1(n - 1, m);
    // C(n, m) = C(n-1, m-1) + C(n-1, m)
}

int binomial_coefficient_2(int n, int m) { // 按照二项式公式递推计算,开辟数组空间开销大
    int C[n + 1][m + 1];
    for (int i = 0; i <= n; i++)
        for (int j = 0; j <= min(i, m); j++) {
            if (j == i || j == 0)
                C[i][j] = 1; // C(n, 0) == c(n, n) == 1
            else
                C[i][j] = C[i - 1][j - 1] + C[i - 1][j]; // C(n, m) = C(n-1, m-1) + C(n-1, m)
        }
    return C[n][m];
}
int main() {
    int n, m;
    scanf("%d %d", &n, &m);
    printf("%d\n", binomial_coefficient_0(n, m));
    printf("%d\n", binomial_coefficient_1(n, m));
    printf("%d\n", binomial_coefficient_2(n, m));
    system("pause");
    return 0;
}
/*
2. 给定一个从小到大排序的链表,向链表中插入一个新的值,要求插入后的链表仍
然是有序的。(15’)

 Definition for singly-linked list.
 struct ListNode {
 int val;
 struct ListNode *next;
 };

// Insert a value into the ordered linked list, returns the head of the new linked list
struct ListNode* Insert(struct ListNode* head, int new_value){
    //write your code here
}
*/
#include <stdio.h>
#include <stdlib.h>

struct ListNode {
    int val;
    struct ListNode* next;
};

struct ListNode* Insert(struct ListNode* head, int new_value) {
    if (head == NULL) {                                                                   // 如果给定的链表本身为空,则返回该新结点
        struct ListNode* new_node = (struct ListNode*)malloc(sizeof(struct ListNode)); // 分配空间
        new_node->val = new_value;                                                       // 赋值
        new_node->next = NULL;                                                           // 初始化
        return new_node;                                                               // 返回该头结点
    }
    else if (head->val >= new_value) {                                                   // 如果新值一开始就比头结点更小,则放到链头
        struct ListNode* new_node = (struct ListNode*)malloc(sizeof(struct ListNode)); // 分配空间
        new_node->val = new_value;                                                       // 赋值
        new_node->next = head;                                                           // 链接到旧的头结点
        return new_node;                                                               // 返回新的头结点
    }
    else if (head->next == NULL) {                                                       // 如果扫描到链表尾部还没找到可插入位置,就放到链尾
        struct ListNode* new_node = (struct ListNode*)malloc(sizeof(struct ListNode)); // 分配空间
        new_node->val = new_value;                                                       // 赋值
        new_node->next = NULL;                                                           // 初始化
        head->next = new_node;                                                           // 与上一个结点相连
        return head;                                                                   // 返回到上一级递归函数调用
    }
    else if ((head->next)->val >= new_value) {                                           // 扫描到可插入位置
        struct ListNode* new_node = (struct ListNode*)malloc(sizeof(struct ListNode)); // 分配空间
        new_node->val = new_value;                                                       // 赋值
        new_node->next = head->next;                                                   // 链接到下一结点
        head->next = new_node;                                                           // 链接到上一结点
        return head;                                                                   // 返回到上一级递归函数调用
    }
    Insert(head->next, new_value); // 递归遍历整个链表
    return head;                   // 返回头结点
}

int main() {
    printf("Please enter the number of node(s): \n");
    int n;
    scanf("%d", &n);
    struct ListNode NodeSet[n];

    printf("Now please enter the value of your %d node(s) in ascending order: \n", n);
    for (int i = 0; i < n - 1; i++) {
        int value;
        scanf("%d", &value);
        NodeSet[i].val = value;
        NodeSet[i].next = &NodeSet[i + 1];
    }
    int value;
    scanf("%d", &value);
    NodeSet[n - 1].val = value;
    NodeSet[n - 1].next = NULL;

    printf("Now please enter the new value: \n");
    int new_value;
    struct ListNode* head;
    scanf("%d", &new_value);
    head = Insert(&NodeSet[0], new_value);

    printf("Now this is your new linked list: \n");
    while (head) {
        printf("%d ", head->val);
        head = head->next;
    }

    putchar('\n');
    system("pause");
    return 0;
}
/*
3. 给定两个从小到大排序的数组,把它们合并成一个数组,保持从小到大的顺序。(20’)
int* MergeArray(int* list1, int size1, int* list2, int size2, int* return_size){
    //write your code here
}
*/
#include <stdio.h>
#include <stdlib.h>

int* MergeArray(int* list1, int size1, int* list2, int size2, int* return_size) {
    *return_size = size1 + size2;
    int* list_merge = (int*)malloc(sizeof(int) * (*return_size));
    int ptr_merge = 0, ptr_list1 = 0, ptr_list2 = 0; // 指向每个数组的当前操作位
    while (ptr_list1 < size1 && ptr_list2 < size2) { // 处理需要比较大小的部分
        if (list1[ptr_list1] <= list2[ptr_list2]) {  // 如果是第一个数组的元素比较小
            list_merge[ptr_merge] = list1[ptr_list1];
            ptr_list1++;
            ptr_merge++;
        }
        else { // 如果是第二个数组的元素比较小
            list_merge[ptr_merge] = list2[ptr_list2];
            ptr_list2++;
            ptr_merge++;
        }
    }
    while (ptr_list1 < size1) { // 如果第一个数组仍有剩余部分
        list_merge[ptr_merge] = list1[ptr_list1];
        ptr_list1++;
        ptr_merge++;
    }
    while (ptr_list2 < size1) { // 如果第一个数组仍有剩余部分
        list_merge[ptr_merge] = list2[ptr_list2];
        ptr_list2++;
        ptr_merge++;
    }
    return list_merge; // 返回数组地址
}

int main() {
    printf("Please enter the size of your first array: \n");
    int size1;
    scanf("%d", &size1);
    int list1[size1];
    printf("Now please enter your first array's %d element(s) in ascending order: \n", size1);
    for (int i = 0; i < size1; i++)
        scanf("%d", &list1[i]);

    printf("Please enter the size of your second array: \n");
    int size2;
    scanf("%d", &size2);
    int list2[size2];
    printf("Now please enter your second array's %d element(s) in ascending order: \n", size2);
    for (int i = 0; i < size2; i++)
        scanf("%d", &list2[i]);

    int size_merge = 0;
    int* list_merge = MergeArray(list1, size1, list2, size2, &size_merge);
    printf("There is your merged array with %d element(s): \n", size_merge);
    for (int i = 0; i < size_merge; i++)
        printf("%d ", list_merge[i]);
    putchar('\n');
    free(list_merge);

    system("pause");
    return 0;
}
/*
4. 给定一个大小为 n*n 的矩阵,计算矩阵的行列式。(20’)
double Determinant(int n , int** matrix){
    //write your code here
}
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
double SubDeterminant_0(int n, int i, int** matrix); // 余子式重整
double Determinant_0(int n, int** matrix); // 行列式按第一行展开
double Determinant_1(int n, int** matrix); // 高斯消元法

int main() {
    printf("Please enter the size of your matrix: \n");
    int n;
    scanf("%d", &n);
    int matrix[n][n];

    printf("Now please enter the element(s) of your matrix: \n");
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            scanf("%d", &matrix[i][j]);

    printf("The determinant of your matrix is : \n%lE\n", Determinant_0(n, (int**)matrix));
    printf("The determinant of your matrix is : \n%lE\n", Determinant_1(n, (int**)matrix));
    system("pause");
    return 0;
}

double Determinant_0(int n, int** matrix) { // 行列式按第一行展开
    int(*array)[n] = (int(*)[n])matrix;        // 将类型名从二重指针转换为二级数组,便于访问
    if (n == 1)
        return array[0][0];
    else {
        double sum = 0, sub_det;
        for (int i = 0; i < n; i++) {                   // 将行列式按第一行展开
            sub_det = SubDeterminant_0(n, i, matrix);  // 计算每一列的余子式
            sum += pow(-1, i) * sub_det * array[0][i]; // 累加代数余子式
        }
        return sum;
    }
}
double SubDeterminant_0(int n, int i, int** matrix) {
    int(*sub_matrix)[n - 1] = (int(*)[n - 1]) malloc(sizeof(int) * (n - 1) * (n - 1));
    int(*array)[n] = (int(*)[n])matrix;
    for (int j = 0; j < n - 1; j++) { // 重新整合余子式对应的矩阵,便于用Determinant_0()来计算
        for (int m = 0; m < n - 1; m++) {
            if (m < i)
                sub_matrix[j][m] = array[j + 1][m];
            else
                sub_matrix[j][m] = array[j + 1][m + 1];
        }
    }
    double sub_det = Determinant_0(n - 1, (int**)sub_matrix); // 继续执行下一级行列式展开
    free(sub_matrix);                                          // 释放空间
    return sub_det;
}

double Determinant_1(int n, int** matrix) { // 高斯消元法
    int(*array)[n] = (int(*)[n])matrix;        // 将类型名从二重指针转换为二级数组,便于访问
    double gauss[n][n];
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            gauss[i][j] = array[i][j]; // 拷贝数据,避免对原数据修改

    for (int diagonal = 0; diagonal < n; diagonal++) {
        if (gauss[diagonal][diagonal] == 0) { // 如果当前对角线元素的值为 0
            int row;
            for (row = diagonal + 1; row < n; row++) // 则从对角线向下搜索直到找到非零数
                if (gauss[row][diagonal] != 0)
                    break;
            if (row == n) // 如果仍然搜索不到非零数
                return 0; // 则该行列式为 0
            for (int col = diagonal; col < n; col++)
                gauss[diagonal][col] += gauss[row][col]; // 将该非零数所在的行,叠加到对角线元素所在的行,使对角线元素不为零
        }                                                 // 保证对角线元素的值非零,用于之后的消元
        for (int row = diagonal + 1; row < n; row++) {
            double ratio = -1 * (gauss[row][diagonal] / gauss[diagonal][diagonal]); // 计算比例
            for (int col = diagonal; col < n; col++)
                gauss[row][col] += ratio * gauss[diagonal][col]; // 消元,将 diagonal列 中的对角线以下元素全部清零
        }                                                         // 转化为上三角行列式
    }
    double det = 1.0;
    for (int i = 0; i < n; i++)
        det *= gauss[i][i]; // 上三角行列式的值等于对角线元素的乘积
    return det;
}
/*
5. 给定两个字符串 a 和 b,判断 a 是否是 b 的子串。例如,当 a=”to”,
b=”cryptography”,a 是 b 的子串;当 a=”red”, b=”read”时,a 不是 b 的子串。(20’)

Given two strings a and b, decide if a is a substring of b.

bool IsSubstring(char* a, char* b){
    //write your code here
}
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAX_LEN 1000

bool IsSubstring(char* a, char* b) {
    int len_a = strlen(a), len_b = strlen(b);
    for (int i = 0; i <= len_b - len_a; i++)
        if (strncmp(a, b + i, len_a) == 0)
            return true;
    return false;
}

int main() {
    char a[MAX_LEN], b[MAX_LEN];
    printf("Please enter string a: \n");
    scanf("%s", a);
    printf("Now please enter string b: \n");
    scanf("%s", b);

    bool judge = IsSubstring(a, b);
    if (judge)
        printf("string a is a substring of b.\n");
    else
        printf("string a is NOT a substring of b.\n");
    system("pause");
    return 0;
}
/*
3. 给定两个从小到大排序的数组,把它们合并成一个数组,保持从小到大的顺序。(20’)
int* MergeArray(int* list1, int size1, int* list2, int size2, int* return_size){
    //write your code here
}
*/
#include <stdio.h>
#include <stdlib.h>

void Move_Hanoi(int n, char A, char B, char C) { // 原版汉诺塔
    if (n == 1)
        printf("%c -> %c\n", A, C);
    else {
        Move_Hanoi(n - 1, A, C, B); // 把上层 n-1 个圆盘从 A 移动到 B
        printf("%c -> %c\n", A, C); // 把最底的第 n 个圆盘从 A 移动到 C
        Move_Hanoi(n - 1, B, A, C); // 把剩余的 n-1 个圆盘从 B 移动到 C
    }
}

void Hanoi(int n) {
    char A = 'A', B = 'B', C = 'C';
    if (n == 1)
        printf("A -> B\n");
    else if (n == 2)
        printf("A -> B\n"
               "A -> C\n");
    else if (n & 2 == 1) {
        Move_Hanoi(n - 1, A, B, C); // 把上层 n-1 个圆盘从 A 移动到 C
        printf("A -> B\n");         // 把最底的第 n 个圆盘(n为奇数) 从 A 移动到 B
        Move_Hanoi(n - 2, C, B, A); // 把剩余的 n-2 个圆盘从 C 移回到 A, 其中第 n-1 个圆盘(偶数)仍留在 C
        Hanoi(n - 2);               // 开始下一次判断
    }
    else {
        Move_Hanoi(n - 1, A, C, B); // 把上层 n-1 个圆盘从 A 移动到 B
        printf("A -> C\n");         // 把最底的第 n 个圆盘(n为偶数) 从 A 移动到 C
        Move_Hanoi(n - 2, B, C, A); // 把剩余的 n-2 个圆盘从 B 移回到 A, 其中第 n-1 个圆盘(奇数)仍留在 B
        Hanoi(n - 2);               // 开始下一次判断
    }
}

int main() {
    printf("Please enter the size of your Hanoi: \n");
    int n;
    scanf("%d", &n);

    printf("There is the movement of your Hanoi: \n");
    Hanoi(n);

    system("pause");
    return 0;
}
posted @ 2023-02-09 08:53  残影0无痕  阅读(53)  评论(0)    收藏  举报