Kỹ thuật lập trình C qua các bài toán thuật toán và cấu trúc điều khiển

1. Chuyển đổi điểm số sang thang điểm chữ

Hàm phanLoaiHocLuc thực hiện việc ánh xạ điểm số hệ 10 sang các ký tự xếp loại (A-E). Logic sử dụng cấu trúc switch-case dựa trên kết quả của phép chia nguyên cho 10.

#include <stdio.h>

char phanLoaiHocLuc(int diem) {
    char ketQua;
    if (diem < 0 || diem > 100) return 'F'; // Trình hợp không hợp lệ
    
    switch (diem / 10) {
        case 10:
        case 9:  ketQua = 'A'; break;
        case 8:  ketQua = 'B'; break;
        case 7:  ketQua = 'C'; break;
        case 6:  ketQua = 'D'; break;
        default: ketQua = 'E'; break;
    }
    return ketQua;
}

int main() {
    int s;
    while (scanf("%d", &s) != EOF) {
        printf("Diem: %d, Xep loai: %c\n", s, phanLoaiHocLuc(s));
    }
    return 0;
}

Lưu ý: Trong cấu trúc switch, lệnh break là bắt buộc để ngăn chương trình thực thi tràn xuống các nhánh bên dưới (fall-through). Nếu thiếu break, kết quả cuối cùng thường sẽ rơi vào trường hợp default.

2. Tính tổng các chữ số của một số nguyên

Bài toán yêu cầu trích xuất từng chữ số của một số nguyên và tính tổng của chúng. Có thể thực hiện bằng phương pháp lặp (iteration) hoặc đệ quy (recursion).

#include <stdio.h>

int tinhTongChuSo(int n) {
    int tong = 0;
    while (n != 0) {
        tong += n % 10; // Lay chu so hang don vi
        n /= 10;        // Loai bo chu so da lay
    }
    return tong;
}

int main() {
    int n;
    while (printf("Nhap n: "), scanf("%d", &n) != EOF) {
        printf("Tong cac chu so cua %d la %d\n", n, tinhTongChuSo(n));
    }
    return 0;
}

3. Tính lũy thừa bằng phương pháp đệ quy tối ưu

Sử dụng thuật toán đệ quy chia để trị nhằm tối ưu hóa việc tính $x^n$. Mô hình toán học chia làm 3 trường hợp: $n=0$, $n$ lẻ và $n$ chẵn.

#include <stdio.h>

long tinhLuyThua(int coSo, int soMu) {
    if (soMu == 0) return 1;
    if (soMu % 2 != 0) {
        return coSo * tinhLuyThua(coSo, soMu - 1);
    } else {
        long tam = tinhLuyThua(coSo, soMu / 2);
        return tam * tam;
    }
}

int main() {
    int x, n;
    while (printf("Nhap x va n: "), scanf("%d%d", &x, &n) != EOF) {
        printf("%d^%d = %ld\n", x, n, tinhLuyThua(x, n));
    }
    return 0;
}

4. Tìm cặp số nguyên tố sinh đôi

Số nguyên tố sinh đôi là cặp số nguyên tố $(p, q)$ sao cho $q = p + 2$. Chương trình tìm các cặp số này trong phạm vi từ 2 đến 100.

#include <stdio.h>
#include <math.h>

int kiemTraNguyenTo(int n) {
    if (n < 2) return 0;
    for (int i = 2; i <= sqrt(n); i++) {
        if (n % i == 0) return 0;
    }
    return 1;
}

int main() {
    int dem = 0;
    printf("Cac cap so nguyen to sinh doi < 100:\n");
    for (int i = 2; i <= 98; i++) {
        if (kiemTraNguyenTo(i) && kiemTraNguyenTo(i + 2)) {
            printf("(%d, %d)\n", i, i + 2);
            dem++;
        }
    }
    printf("Tong cong: %d cap\n", dem);
    return 0;
}

5. Giải bài toán Tháp Hà Nội

Bài toán kinh điển minh họa sức mạnh của đệ quy. Để chuyển $n$ đĩa từ cọc A sang cọc C, ta chuyển $n-1$ đĩa sang cọc trung gian B, di chuyển đĩa lớn nhất sang C, sau đó chuyển $n-1$ đĩa từ B sang C.

#include <stdio.h>

unsigned long buocDi = 0;

void diChuyenDia(int soHieu, char tu, char den) {
    printf("Buoc %lu: Di chuyen dia %d tu %c sang %c\n", ++buocDi, soHieu, tu, den);
}

void giaiHanoi(int n, char nguon, char trungGian, char dich) {
    if (n == 1) {
        diChuyenDia(1, nguon, dich);
    } else {
        giaiHanoi(n - 1, nguon, dich, trungGian);
        diChuyenDia(n, nguon, dich);
        giaiHanoi(n - 1, trungGian, nguon, dich);
    }
}

int main() {
    int n;
    while (scanf("%d", &n) != EOF) {
        buocDi = 0;
        giaiHanoi(n, 'A', 'B', 'C');
        printf("Tong so buoc: %lu\n", buocDi);
    }
    return 0;
}

6. Tính tổ hợp C(n, m) bằng hai cách

Cách 1 sử dụng công thức đệ quy Pascal: $C(n, k) = C(n-1, k) + C(n-1, k-1)$. Cách 2 sử dụng công thức giai thừa thông qua vòng lặp.

#include <stdio.h>

// Cach 1: De quy
int toHopDeQuy(int n, int m) {
    if (m == 0 || m == n) return 1;
    if (m > n) return 0;
    return toHopDeQuy(n - 1, m) + toHopDeQuy(n - 1, m - 1);
}

// Cach 2: Giai thua (Lap)
long giaiThua(int n) {
    long f = 1;
    for (int i = 1; i <= n; i++) f *= i;
    return f;
}

int main() {
    int n, m;
    while (scanf("%d%d", &n, &m) != EOF) {
        printf("De quy: C(%d, %d) = %d\n", n, m, toHopDeQuy(n, m));
        long kqLap = giaiThua(n) / (giaiThua(m) * giaiThua(n - m));
        printf("Vong lap: C(%d, %d) = %ld\n", n, m, kqLap);
    }
    return 0;
}

7. In mô hình đồ họa ký tự

Sử dụng đệ quy và vòng lặp lồng nhau để tạo ra các mô hình ký tự phức tạp trên màn hình console.

#include <stdio.h>

int khoangCach = 0;

void veHinh(int n) {
    if (n <= 0) return;

    for (int i = 0; i < khoangCach; i++) printf("\t");
    for (int j = 0; j < 2 * n - 1; j++) printf(" O      ");
    printf("\n");

    for (int i = 0; i < khoangCach; i++) printf("\t");
    for (int j = 0; j < 2 * n - 1; j++) printf("<H>\t");
    printf("\n");

    for (int i = 0; i < khoangCach; i++) printf("\t");
    for (int j = 0; j < 2 * n - 1; j++) printf("I I\t");
    printf("\n");

    khoangCach++;
    veHinh(n - 1);
}

int main() {
    int n;
    printf("Nhap n: ");
    if (scanf("%d", &n) != EOF) {
        veHinh(n);
    }
    return 0;
}

Thẻ: c-programming Algorithms Recursion Combinatorics tower-of-hanoi

Đăng vào ngày 27 tháng 10 lúc 21:23