Bài 9.5. Bài tập tổng hợp về mảng hai chiều

Chào mừng các bạn quay trở lại với series về Cấu trúc dữ liệu và Giải thuật của FullhouseDev!

Sau khi đã làm quen với lý thuyết về mảng hai chiều (hay còn gọi là ma trận) trong các bài trước, bây giờ là lúc chúng ta thực hành để củng cố kiến thức. Mảng hai chiều là một cấu trúc dữ liệu rất phổ biến và có nhiều ứng dụng, từ xử lý ảnh, trò chơi, đến các bài toán khoa học. Việc nắm vững cách thao tác với chúng là cực kỳ quan trọng.

Bài viết này sẽ tập trung vào các bài tập thực hành cơ bản đến nâng cao một chút về mảng hai chiều trong C++. Chúng ta sẽ cùng nhau đi qua từng bài, phân tích yêu cầu và triển khai code, đồng thời giải thích chi tiết từng dòng lệnh.

Hãy cùng bắt tay vào nào!

Bài tập 1: Nhập và Xuất mảng hai chiều

Bài tập cơ bản nhất là biết cách nhập dữ liệu vào mảng hai chiều từ bàn phím và xuất nội dung của nó ra màn hình một cách có định dạng.

Yêu cầu: Viết chương trình C++ cho phép người dùng nhập số hàng (m) và số cột (n), sau đó nhập các phần tử cho mảng kích thước m x n, và cuối cùng là in mảng ra màn hình theo định dạng ma trận.

Code minh hoạ:

#include <iostream>
#include <vector>
#include <iomanip> // Để định dạng hiển thị

int main() {
    int m, n;

    std::cout << "Nhap so hang (m): ";
    std::cin >> m;
    std::cout << "Nhap so cot (n): ";
    std::cin >> n;

    // Khai bao mang hai chieu su dung vector<vector<int>>
    // Day la cach linh hoat hon so voi mang co dinh kich thuoc
    std::vector<std::vector<int>> matrix(m, std::vector<int>(n));

    std::cout << "Nhap cac phan tu cua mang:" << std::endl;
    // Vong lap de nhap du lieu
    // Vong lap ngoai: duyet qua cac hang (i)
    for (int i = 0; i < m; ++i) {
        // Vong lap ben trong: duyet qua cac cot (j) trong moi hang
        for (int j = 0; j < n; ++j) {
            std::cout << "Nhap phan tu a[" << i << "][" << j << "]: ";
            std::cin >> matrix[i][j]; // Truy cap va gan gia tri cho phan tu
        }
    }

    std::cout << "\nMang da nhap la:" << std::endl;
    // Vong lap de in mang ra man hinh
    // Vong lap ngoai: duyet qua cac hang (i)
    for (int i = 0; i < m; ++i) {
        // Vong lap ben trong: duyet qua cac cot (j) trong moi hang
        for (int j = 0; j < n; ++j) {
            // In tung phan tu, su dung setw de can le cho dep mat
            std::cout << std::setw(5) << matrix[i][j];
        }
        std::cout << std::endl; // Xuong dong sau khi ket thuc mot hang
    }

    return 0;
}

Giải thích code:

  1. Chúng ta sử dụng std::vector<std::vector<int>> để tạo một mảng hai chiều động. Cách này linh hoạt hơn so với mảng C-style cố định kích thước, cho phép chúng ta xác định kích thước khi chương trình chạy.
  2. matrix(m, std::vector<int>(n)): Dòng này tạo ra một vector chứa m phần tử. Mỗi phần tử này lại là một vector<int> có kích thước n. Đây chính là cách biểu diễn m hàng và n cột.
  3. Việc nhập và xuất mảng đều sử dụng hai vòng lặp lồng nhau.
    • Vòng lặp ngoài thường duyệt qua các hàng (index i).
    • Vòng lặp trong thường duyệt qua các cột (index j) trong hàng hiện tại.
  4. Để truy cập đến một phần tử tại hàng i và cột j, chúng ta dùng cú pháp matrix[i][j].
  5. Khi in, chúng ta in từng phần tử của một hàng trên cùng một dòng, sau đó xuống dòng bằng std::endl sau khi in hết một hàng để tạo định dạng ma trận. std::setw(5) được dùng để đảm bảo mỗi số chiếm ít nhất 5 ký tự khi in, giúp các cột thẳng hàng hơn.
Bài tập 2: Tính tổng các phần tử trong mảng

Sau khi biết cách nhập xuất, bài tập tiếp theo là thực hiện một thao tác đơn giản trên tất cả các phần tử.

Yêu cầu: Tính tổng của tất cả các phần tử có trong mảng hai chiều m x n đã nhập.

Code minh hoạ:

#include <iostream>
#include <vector>

int main() {
    int m, n;

    // ... (Phan nhap mang tuong tu Bai tap 1) ...
    std::cout << "Nhap so hang (m): ";
    std::cin >> m;
    std::cout << "Nhap so cot (n): ";
    std::cin >> n;

    std::vector<std::vector<int>> matrix(m, std::vector<int>(n));

    std::cout << "Nhap cac phan tu cua mang:" << std::endl;
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            std::cout << "Nhap phan tu a[" << i << "][" << j << "]: ";
            std::cin >> matrix[i][j];
        }
    }

    // ... (Het phan nhap mang) ...

    long long totalSum = 0; // Su dung long long de phong tong qua lon

    // Vong lap de tinh tong
    // Duyet qua tat ca cac hang
    for (int i = 0; i < m; ++i) {
        // Duyet qua tat ca cac cot trong hang hien tai
        for (int j = 0; j < n; ++j) {
            totalSum += matrix[i][j]; // Cong gia tri cua phan tu hien tai vao tong
        }
    }

    std::cout << "\nTong cua tat ca cac phan tu trong mang la: " << totalSum << std::endl;

    return 0;
}

Giải thích code:

  1. Chúng ta khởi tạo một biến totalSum với giá trị ban đầu là 0. Nên dùng kiểu long long để đảm bảo rằng tổng không bị tràn số nếu mảng chứa các giá trị lớn hoặc có kích thước rất lớn.
  2. Lại sử dụng hai vòng lặp lồng nhau để duyệt qua tất cả các phần tử trong mảng, giống như khi nhập hoặc xuất.
  3. Bên trong vòng lặp trong cùng, chúng ta truy cập đến phần tử matrix[i][j]cộng giá trị của nó vào biến totalSum.
  4. Sau khi kết thúc cả hai vòng lặp, biến totalSum sẽ chứa tổng của tất cả các phần tử trong mảng.
Bài tập 3: Tìm phần tử lớn nhất và nhỏ nhất

Một bài tập kinh điển khác là tìm giá trị cực trị trong mảng.

Yêu cầu: Tìm và in ra giá trị lớn nhất và giá trị nhỏ nhất trong mảng hai chiều đã nhập.

Code minh hoạ:

#include <iostream>
#include <vector>
#include <limits> // Cho numeric_limits

int main() {
    int m, n;

    // ... (Phan nhap mang tuong tu Bai tap 1) ...
    std::cout << "Nhap so hang (m): ";
    std::cin >> m;
    std::cout << "Nhap so cot (n): ";
    std::cin >> n;

    // Kiem tra mang rong
    if (m <= 0 || n <= 0) {
        std::cout << "Kich thuoc mang khong hop le!" << std::endl;
        return 1; // Thoat neu kich thuoc khong hop le
    }

    std::vector<std::vector<int>> matrix(m, std::vector<int>(n));

    std::cout << "Nhap cac phan tu cua mang:" << std::endl;
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            std::cout << "Nhap phan tu a[" << i << "][" << j << "]: ";
            std::cin >> matrix[i][j];
        }
    }
    // ... (Het phan nhap mang) ...

    // Khoi tao gia tri lon nhat va nho nhat
    // Cach 1: Gan bang phan tu dau tien (can dam bao mang khong rong)
    // int maxVal = matrix[0][0];
    // int minVal = matrix[0][0];

    // Cach 2: Gan bang gia tri cuc tieu/cuc dai cua kieu du lieu
    int maxVal = std::numeric_limits<int>::min(); // Gia tri int nho nhat co the
    int minVal = std::numeric_limits<int>::max(); // Gia tri int lon nhat co the


    // Vong lap de tim max va min
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            // So sanh va cap nhat gia tri lon nhat
            if (matrix[i][j] > maxVal) {
                maxVal = matrix[i][j];
            }
            // So sanh va cap nhat gia tri nho nhat
            if (matrix[i][j] < minVal) {
                minVal = matrix[i][j];
            }
        }
    }

    std::cout << "\nGia tri lon nhat trong mang la: " << maxVal << std::endl;
    std::cout << "Gia tri nho nhat trong mang la: " << minVal << std::endl;

    return 0;
}

Giải thích code:

  1. Trước khi bắt đầu tìm kiếm, chúng ta cần một giá trị khởi tạo cho maxValminVal.
    • Một cách là gán chúng bằng giá trị của phần tử đầu tiên (matrix[0][0]). Sau đó, chúng ta duyệt qua tất cả các phần tử (bao gồm cả phần tử đầu tiên, hoặc bắt đầu duyệt từ phần tử thứ hai nếu bạn chắc chắn mang có ít nhất 2 phần tử) và so sánh. Lưu ý: Cách này yêu cầu bạn phải xử lý trường hợp mảng rỗng.
    • Cách an toàn hơn là khởi tạo maxVal bằng giá trị nhỏ nhất có thể của kiểu dữ liệu (std::numeric_limits<int>::min()) và minVal bằng giá trị lớn nhất có thể (std::numeric_limits<int>::max()). Bằng cách này, bất kỳ phần tử nào trong mảng (nếu mảng không rỗng) cũng sẽ lớn hơn maxVal ban đầu và nhỏ hơn minVal ban đầu, đảm bảo chúng được cập nhật đúng.
  2. Sử dụng hai vòng lặp lồng nhau để duyệt qua mọi phần tử.
  3. Trong mỗi lần lặp, chúng ta so sánh giá trị của phần tử hiện tại matrix[i][j] với maxValminVal đang giữ.
  4. Nếu matrix[i][j] lớn hơn maxVal, chúng ta cập nhật maxVal bằng giá trị của phần tử đó.
  5. Nếu matrix[i][j] nhỏ hơn minVal, chúng ta cập nhật minVal bằng giá trị của phần tử đó.
  6. Sau khi duyệt xong, maxValminVal sẽ lưu trữ giá trị lớn nhất và nhỏ nhất tìm được.
Bài tập 4: Tính tổng các phần tử trên một hàng hoặc một cột cụ thể

Đôi khi chúng ta chỉ cần làm việc với một phần của mảng, ví dụ như một hàng hoặc một cột riêng lẻ.

Yêu cầu: Nhập vào số thứ tự của một hàng (R) và một cột (C). Tính tổng các phần tử trên hàng R và tổng các phần tử trên cột C.

Code minh hoạ:

#include <iostream>
#include <vector>

int main() {
    int m, n;

    // ... (Phan nhap mang tuong tu Bai tap 1) ...
    std::cout << "Nhap so hang (m): ";
    std::cin >> m;
    std::cout << "Nhap so cot (n): ";
    std::cin >> n;

    if (m <= 0 || n <= 0) {
        std::cout << "Kich thuoc mang khong hop le!" << std::endl;
        return 1;
    }

    std::vector<std::vector<int>> matrix(m, std::vector<int>(n));

    std::cout << "Nhap cac phan tu cua mang:" << std::endl;
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            std::cout << "Nhap phan tu a[" << i << "][" << j << "]: ";
            std::cin >> matrix[i][j];
        }
    }
    // ... (Het phan nhap mang) ...

    int rowIdx, colIdx;

    std::cout << "\nNhap so thu tu hang can tinh tong (0 den " << m - 1 << "): ";
    std::cin >> rowIdx;

    // Kiem tra chi so hang hop le
    if (rowIdx < 0 || rowIdx >= m) {
        std::cout << "Chi so hang khong hop le!" << std::endl;
        return 1;
    }

    // Tinh tong hang
    long long rowSum = 0;
    // Chi can mot vong lap de duyet qua cac cot trong hang rowIdx
    for (int j = 0; j < n; ++j) {
        rowSum += matrix[rowIdx][j]; // Hang co dinh la rowIdx, cot chay tu 0 den n-1
    }
    std::cout << "Tong cac phan tu tren hang " << rowIdx << " la: " << rowSum << std::endl;

    std::cout << "Nhap so thu tu cot can tinh tong (0 den " << n - 1 << "): ";
    std::cin >> colIdx;

    // Kiem tra chi so cot hop le
    if (colIdx < 0 || colIdx >= n) {
        std::cout << "Chi so cot khong hop le!" << std::endl;
        return 1;
    }

    // Tinh tong cot
    long long colSum = 0;
    // Chi can mot vong lap de duyet qua cac hang trong cot colIdx
    for (int i = 0; i < m; ++i) {
        colSum += matrix[i][colIdx]; // Cot co dinh la colIdx, hang chay tu 0 den m-1
    }
    std::cout << "Tong cac phan tu tren cot " << colIdx << " la: " << colSum << std::endl;

    return 0;
}

Giải thích code:

  1. Sau khi nhập mảng và chỉ số hàng (rowIdx), chúng ta cần kiểm tra xem chỉ số này có hợp lệ hay không (nằm trong khoảng từ 0 đến m-1).
  2. Để tính tổng một hàng cụ thể (rowIdx), chúng ta chỉ cần một vòng lặp. Vòng lặp này sẽ duyệt qua tất cả các cột (từ 0 đến n-1), trong khi chỉ số hàng được giữ cố địnhrowIdx. Chúng ta truy cập phần tử bằng matrix[rowIdx][j].
  3. Tương tự, để tính tổng một cột cụ thể (colIdx), chúng ta cũng chỉ cần một vòng lặp. Vòng lặp này sẽ duyệt qua tất cả các hàng (từ 0 đến m-1), trong khi chỉ số cột được giữ cố địnhcolIdx. Chúng ta truy cập phần tử bằng matrix[i][colIdx].
  4. Việc sử dụng một vòng lặp thay vì hai vòng lặp lồng nhau là điểm khác biệt chính ở đây, vì chúng ta chỉ xử lý một dòng hoặc một cột riêng biệt, chứ không phải toàn bộ mảng.
Bài tập 5: Tính tổng các phần tử trên đường chéo chính (Chỉ áp dụng cho mảng vuông)

Đối với các ma trận vuông (số hàng bằng số cột), chúng ta có thể nói đến các đường chéo. Đường chéo chính chứa các phần tử mà chỉ số hàng bằng chỉ số cột (matrix[i][i]).

Yêu cầu: Cho một mảng vuông kích thước n x n. Tính tổng các phần tử nằm trên đường chéo chính.

Code minh hoạ:

#include <iostream>
#include <vector>

int main() {
    int n; // Vi la mang vuong nen chi can mot kich thuoc n

    std::cout << "Nhap kich thuoc cua mang vuong (n): ";
    std::cin >> n;

    if (n <= 0) {
        std::cout << "Kich thuoc mang khong hop le!" << std::endl;
        return 1;
    }

    std::vector<std::vector<int>> matrix(n, std::vector<int>(n));

    std::cout << "Nhap cac phan tu cua mang vuong " << n << "x" << n << ":" << std::endl;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            std::cout << "Nhap phan tu a[" << i << "][" << j << "]: ";
            std::cin >> matrix[i][j];
        }
    }

    long long mainDiagonalSum = 0;

    // Vong lap de tinh tong duong cheo chinh
    // Chi can mot vong lap vi chi so hang va cot bang nhau (i == j)
    for (int i = 0; i < n; ++i) {
        mainDiagonalSum += matrix[i][i]; // Truy cap phan tu tai matrix[i][i]
    }

    std::cout << "\nTong cac phan tu tren duong cheo chinh la: " << mainDiagonalSum << std::endl;

    return 0;
}

Giải thích code:

  1. Bài tập này chỉ áp dụng cho mảng vuông, nên chúng ta chỉ cần nhập một kích thước n (số hàng = số cột = n).
  2. Các phần tử trên đường chéo chính có đặc điểm là chỉ số hàng và chỉ số cột của chúng luôn bằng nhau (i == j).
  3. Do đó, chúng ta chỉ cần một vòng lặp duy nhất, chạy từ 0 đến n-1. Trong mỗi lần lặp, chúng ta truy cập đến phần tử matrix[i][i] (vì i vừa là chỉ số hàng, vừa là chỉ số cột) và cộng nó vào tổng mainDiagonalSum.
Bài tập 6: Tính tổng các phần tử trên đường chéo phụ (Chỉ áp dụng cho mảng vuông)

Đường chéo phụ (hay còn gọi là đường chéo anti-diagonal hoặc counter-diagonal) cũng chỉ có ở mảng vuông. Các phần tử trên đường chéo phụ có tổng chỉ số hàng và chỉ số cột bằng n - 1, với n là kích thước của ma trận vuông (i + j == n - 1).

Yêu cầu: Cho một mảng vuông kích thước n x n. Tính tổng các phần tử nằm trên đường chéo phụ.

Code minh hoạ:

#include <iostream>
#include <vector>

int main() {
    int n;

    // ... (Phan nhap mang vuong tuong tu Bai tap 5) ...
    std::cout << "Nhap kich thuoc cua mang vuong (n): ";
    std::cin >> n;

    if (n <= 0) {
        std::cout << "Kich thuoc mang khong hop le!" << std::endl;
        return 1;
    }

    std::vector<std::vector<int>> matrix(n, std::vector<int>(n));

    std::cout << "Nhap cac phan tu cua mang vuong " << n << "x" << n << ":" << std::endl;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            std::cout << "Nhap phan tu a[" << i << "][" << j << "]: ";
            std::cin >> matrix[i][j];
        }
    }
    // ... (Het phan nhap mang) ...

    long long antiDiagonalSum = 0;

    // Vong lap de tinh tong duong cheo phu
    // Chi can mot vong lap. Chi so cot j se la n - 1 - i
    for (int i = 0; i < n; ++i) {
        // Chi so hang la i, chi so cot tuong ung la n - 1 - i
        int j = n - 1 - i;
        antiDiagonalSum += matrix[i][j]; // Truy cap phan tu tai matrix[i][n-1-i]
    }

    std::cout << "\nTong cac phan tu tren duong cheo phu la: " << antiDiagonalSum << std::endl;

    return 0;
}

Giải thích code:

  1. Bài tập này cũng chỉ áp dụng cho mảng vuông kích thước n x n.
  2. Các phần tử trên đường chéo phụ có đặc điểm là tổng chỉ số hàng và chỉ số cột luôn bằng n - 1 (i + j = n - 1). Điều này có nghĩa là nếu chúng ta biết chỉ số hàng i, thì chỉ số cột tương ứng trên đường chéo phụ sẽ là j = n - 1 - i.
  3. Tương tự đường chéo chính, chúng ta chỉ cần một vòng lặp duy nhất, duyệt qua các hàng (từ 0 đến n-1). Trong mỗi lần lặp với chỉ số hàng i, chúng ta tính chỉ số cột tương ứng là n - 1 - i và truy cập phần tử matrix[i][n - 1 - i], sau đó cộng nó vào tổng antiDiagonalSum.
Bài tập 7: Chuyển vị ma trận (Transpose)

Phép chuyển vị (transpose) của một ma trận là tạo ra một ma trận mới mà các hàng của ma trận gốc trở thành các cột của ma trận mới, và ngược lại. Nếu ma trận gốc có kích thước m x n, ma trận chuyển vị sẽ có kích thước n x m. Phần tử tại [i][j] của ma trận gốc sẽ nằm tại [j][i] của ma trận chuyển vị.

Yêu cầu: Cho ma trận kích thước m x n. Tạo và in ra ma trận chuyển vị của nó.

Code minh hoạ:

#include <iostream>
#include <vector>
#include <iomanip>

int main() {
    int m, n;

    // ... (Phan nhap mang tuong tu Bai tap 1) ...
    std::cout << "Nhap so hang (m): ";
    std::cin >> m;
    std::cout << "Nhap so cot (n): ";
    std::cin >> n;

    if (m <= 0 || n <= 0) {
        std::cout << "Kich thuoc mang khong hop le!" << std::endl;
        return 1;
    }

    std::vector<std::vector<int>> matrix(m, std::vector<int>(n));

    std::cout << "Nhap cac phan tu cua mang:" << std::endl;
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            std::cout << "Nhap phan tu a[" << i << "][" << j << "]: ";
            std::cin >> matrix[i][j];
        }
    }
    // ... (Het phan nhap mang) ...

    // Tao ma tran chuyen vi
    // Kich thuoc ma tran chuyen vi la n x m (so hang = so cot goc, so cot = so hang goc)
    std::vector<std::vector<int>> transposedMatrix(n, std::vector<int>(m));

    // Vong lap de thuc hien chuyen vi
    // Duyet qua cac phan tu cua ma tran goc
    for (int i = 0; i < m; ++i) { // Duyet qua hang cua ma tran goc
        for (int j = 0; j < n; ++j) { // Duyet qua cot cua ma tran goc
            // Gan phan tu tai [i][j] cua goc vao vi tri [j][i] cua ma tran chuyen vi
            transposedMatrix[j][i] = matrix[i][j];
        }
    }

    std::cout << "\nMa tran chuyen vi la:" << std::endl;
    // In ma tran chuyen vi (kich thuoc n x m)
    for (int i = 0; i < n; ++i) { // Duyet qua hang cua ma tran chuyen vi (n hang)
        for (int j = 0; j < m; ++j) { // Duyet qua cot cua ma tran chuyen vi (m cot)
            std::cout << std::setw(5) << transposedMatrix[i][j];
        }
        std::cout << std::endl;
    }

    return 0;
}

Giải thích code:

  1. Đầu tiên, chúng ta khai báo một ma trận mới có tên transposedMatrix. Kích thước của nó sẽ là n x m, ngược lại với ma trận gốc m x n.
  2. Sử dụng hai vòng lặp lồng nhau để duyệt qua tất cả các phần tử của ma trận gốc (matrix), với chỉ số hàng i và chỉ số cột j.
  3. Đối với mỗi phần tử matrix[i][j] trong ma trận gốc, chúng ta gán giá trị của nó vào vị trí ngược lạitransposedMatrix[j][i] trong ma trận chuyển vị. Đây chính là cốt lõi của phép chuyển vị.
  4. Cuối cùng, chúng ta in ma trận transposedMatrix ra màn hình. Chú ý rằng khi in, chúng ta duyệt transposedMatrix theo kích thước của nó là n x m (vòng lặp ngoài từ 0 đến n-1, vòng lặp trong từ 0 đến m-1).
Bài tập 8: Kiểm tra ma trận đối xứng (Chỉ áp dụng cho mảng vuông)

Một ma trận vuông được gọi là đối xứng nếu nó bằng chính ma trận chuyển vị của nó. Điều này có nghĩa là phần tử tại vị trí [i][j] phải bằng phần tử tại vị trí [j][i] cho tất cả các cặp chỉ số i, j.

Yêu cầu: Cho một mảng vuông kích thước n x n. Kiểm tra xem nó có phải là ma trận đối xứng hay không.

Code minh hoạ:

#include <iostream>
#include <vector>

int main() {
    int n;

    // ... (Phan nhap mang vuong tuong tu Bai tap 5) ...
    std::cout << "Nhap kich thuoc cua mang vuong (n): ";
    std::cin >> n;

    if (n <= 0) {
        std::cout << "Kich thuoc mang khong hop le!" << std::endl;
        return 1;
    }

    std::vector<std::vector<int>> matrix(n, std::vector<int>(n));

    std::cout << "Nhap cac phan tu cua mang vuong " << n << "x" << n << ":" << std::endl;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            std::cout << "Nhap phan tu a[" << i << "][" << j << "]: ";
            std::cin >> matrix[i][j];
        }
    }
    // ... (Het phan nhap mang) ...

    bool isSymmetric = true; // Gia su ban dau la doi xung

    // Vong lap kiem tra tinh doi xung
    // Chi can kiem tra nua tren (hoac nua duoi) cua ma tran, khong can duong cheo chinh
    for (int i = 0; i < n; ++i) {
        // Duyet cot j tu i + 1 de chi kiem tra cac phan tu phia tren duong cheo chinh
        for (int j = i + 1; j < n; ++j) {
            // Neu tim thay cap nao ma matrix[i][j] != matrix[j][i]
            if (matrix[i][j] != matrix[j][i]) {
                isSymmetric = false; // thi ma tran khong doi xung
                break; // Thoat vong lap trong
            }
        }
        if (!isSymmetric) {
            break; // Thoat vong lap ngoai neu da tim thay cap khong doi xung
        }
    }

    // In ket qua
    if (isSymmetric) {
        std::cout << "\nMa tran la ma tran doi xung." << std::endl;
    } else {
        std::cout << "\nMa tran khong phai la ma tran doi xung." << std::endl;
    }

    return 0;
}

Giải thích code:

  1. Bài tập này chỉ áp dụng cho mảng vuông kích thước n x n.
  2. Chúng ta khởi tạo một biến boolean isSymmetric với giá trị true, giả định ban đầu rằng ma trận là đối xứng. Chúng ta sẽ chuyển nó thành false nếu tìm thấy bằng chứng ngược lại.
  3. Để kiểm tra tính đối xứng (matrix[i][j] == matrix[j][i] cho mọi i, j), chúng ta không cần phải kiểm tra tất cả các cặp. Nếu matrix[i][j] đã được so sánh với matrix[j][i], thì cặp matrix[j][i] so sánh với matrix[i][j]thừa. Hơn nữa, các phần tử trên đường chéo chính (matrix[i][i]) luôn bằng chính nó, nên chúng ta cũng không cần kiểm tra.
  4. Vì vậy, chúng ta chỉ cần duyệt qua một nửa ma trận (ví dụ: nửa phía trên đường chéo chính). Vòng lặp ngoài duyệt hàng i từ 0 đến n-1. Vòng lặp trong duyệt cột j từ i + 1 đến n-1. Bắt đầu j từ i + 1 đảm bảo chúng ta chỉ xét các phần tử phía trên đường chéo chính và không lặp lại các cặp đã xét.
  5. Trong mỗi lần lặp, chúng ta so sánh matrix[i][j] với matrix[j][i].
  6. Nếu bất kỳ lúc nào chúng ta tìm thấy một cặp mà matrix[i][j] khác matrix[j][i], thì ma trận không đối xứng. Chúng ta đặt isSymmetric thành false và sử dụng break để thoát ngay lập tức khỏi các vòng lặp, vì không cần kiểm tra thêm nữa.
  7. Nếu các vòng lặp hoàn thành mà không tìm thấy cặp nào không thỏa mãn điều kiện đối xứng, thì isSymmetric vẫn giữ giá trị true, và ma trận là đối xứng.

Chúc các bạn học tốt!

Bài tập ví dụ:

Sắp xếp các phần tử theo cột.

Cho ma trận vuông cỡ NxN gồm N hàng, mỗi hàng N cột. Hãy sắp xếp các phần tử trong ma trận theo cột theo thứ tự tăng dần.

Input Format

Dòng đầu tiên là số N. N dòng tiếp theo mỗi dòng có N số. (1≤n≤200; Các phần tử trong ma trận là số dương không quá 10^9)

Constraints

In ra ma trận sau khi đã sắp xếp theo cột tăng dần.

Output Format

In ra ma trận sau khi đã sắp xếp theo cột tăng dần.

Ví dụ:

Dữ liệu vào
5
1 2 3 4 5
10 9 7 6 8
23 12 2 14 15
16 7 18 19 20
25 24 23 22 1
Dữ liệu ra
1 2 2 4 1
10 7 3 6 5
16 9 7 14 8
23 12 18 19 15
25 24 23 22 20

Okay, đây là hướng dẫn giải bài "Sắp xếp các phần tử theo cột" bằng C++ một cách ngắn gọn, không cung cấp code hoàn chỉnh.

  1. Đọc Input: Đọc kích thước ma trận N. Sau đó, đọc N*N phần tử để lưu vào ma trận (sử dụng mảng 2 chiều hoặc vector<vector<int>>).

  2. Lặp qua từng cột: Bài toán yêu cầu sắp xếp theo cột, nghĩa là mỗi cột được xử lý độc lập. Do đó, bạn cần một vòng lặp ngoài chạy từ cột j = 0 đến N-1.

  3. Xử lý cho mỗi cột j:

    • Trích xuất: Tạo một mảng/vector tạm có kích thước N. Lặp qua các hàng i = 0 đến N-1 và sao chép phần tử ma_tran[i][j] vào mảng/vector tạm này.
    • Sắp xếp: Sử dụng hàm sắp xếp có sẵn (std::sort trong C++ là lựa chọn hiệu quả) để sắp xếp các phần tử trong mảng/vector tạm theo thứ tự tăng dần.
    • Ghi lại: Lặp lại qua các hàng i = 0 đến N-1 và ghi các phần tử đã được sắp xếp từ mảng/vector tạm trở lại vị trí ma_tran[i][j] trong ma trận gốc.
  4. In Output: Sau khi đã thực hiện bước 3 cho tất cả các cột, ma trận đã được sắp xếp theo yêu cầu. In ma trận ra màn hình, đảm bảo định dạng giống ví dụ (các số trên cùng một hàng cách nhau bằng khoảng trắng, mỗi hàng trên một dòng mới).

Tóm lại các bước logic:

  • Đọc N và ma trận.
  • Với mỗi cột j từ 0 đến N-1:
    • Thu thập các phần tử của cột j vào một mảng tạm.
    • Sắp xếp mảng tạm.
    • Ghi lại các phần tử đã sắp xếp vào cột j của ma trận.
  • In ma trận kết quả.

Làm thêm nhiều bài tập miễn phí tại đây

Comments

There are no comments at the moment.