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

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:
- 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. matrix(m, std::vector<int>(n))
: Dòng này tạo ra mộtvector
chứam
phần tử. Mỗi phần tử này lại là mộtvector<int>
có kích thướcn
. Đây chính là cách biểu diễnm
hàng vàn
cột.- 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.
- Vòng lặp ngoài thường duyệt qua các hàng (index
- Để truy cập đến một phần tử tại hàng
i
và cộtj
, chúng ta dùng cú phápmatrix[i][j]
. - 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:
- 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ểulong 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. - 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.
- Bên trong vòng lặp trong cùng, chúng ta truy cập đến phần tử
matrix[i][j]
và cộng giá trị của nó vào biếntotalSum
. - 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:
- Trước khi bắt đầu tìm kiếm, chúng ta cần một giá trị khởi tạo cho
maxVal
vàminVal
.- 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ơnmaxVal
ban đầu và nhỏ hơnminVal
ban đầu, đảm bảo chúng được cập nhật đúng.
- Một cách là gán chúng bằng giá trị của phần tử đầu tiên (
- Sử dụng hai vòng lặp lồng nhau để duyệt qua mọi phần tử.
- 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ớimaxVal
vàminVal
đang giữ. - Nếu
matrix[i][j]
lớn hơnmaxVal
, chúng ta cập nhậtmaxVal
bằng giá trị của phần tử đó. - Nếu
matrix[i][j]
nhỏ hơnminVal
, chúng ta cập nhậtminVal
bằng giá trị của phần tử đó. - Sau khi duyệt xong,
maxVal
vàminVal
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:
- 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 đếnm-1
). - Để 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 đếnn-1
), trong khi chỉ số hàng được giữ cố định làrowIdx
. Chúng ta truy cập phần tử bằngmatrix[rowIdx][j]
. - 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 đếnm-1
), trong khi chỉ số cột được giữ cố định làcolIdx
. Chúng ta truy cập phần tử bằngmatrix[i][colIdx]
. - 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:
- 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
). - 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
). - 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ổngmainDiagonalSum
.
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:
- Bài tập này cũng chỉ áp dụng cho mảng vuông kích thước
n x n
. - 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àngi
, thì chỉ số cột tương ứng trên đường chéo phụ sẽ làj = n - 1 - i
. - 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àngi
, 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ổngantiDiagonalSum
.
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:
- Đầ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. - 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àngi
và chỉ số cộtj
. - Đố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ại làtransposedMatrix[j][i]
trong ma trận chuyển vị. Đây chính là cốt lõi của phép chuyển vị. - 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ệttransposedMatrix
theo kích thước của nó là n x m (vòng lặp ngoài từ 0 đếnn-1
, vòng lặp trong từ 0 đếnm-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:
- Bài tập này chỉ áp dụng cho mảng vuông kích thước
n x n
. - 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ànhfalse
nếu tìm thấy bằng chứng ngược lại. - Để kiểm tra tính đối xứng (
matrix[i][j] == matrix[j][i]
cho mọii, j
), chúng ta không cần phải kiểm tra tất cả các cặp. Nếumatrix[i][j]
đã được so sánh vớimatrix[j][i]
, thì cặpmatrix[j][i]
so sánh vớimatrix[i][j]
là 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. - 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 đếnn-1
. Vòng lặp trong duyệt cộtj
từi + 1
đếnn-1
. Bắt đầuj
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. - Trong mỗi lần lặp, chúng ta so sánh
matrix[i][j]
vớimatrix[j][i]
. - 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ácmatrix[j][i]
, thì ma trận không đối xứng. Chúng ta đặtisSymmetric
thànhfalse
và sử dụngbreak
để 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. - 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.
Đọc Input: Đọc kích thước ma trận
N
. Sau đó, đọcN*N
phần tử để lưu vào ma trận (sử dụng mảng 2 chiều hoặcvector<vector<int>>
).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
đếnN-1
.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àngi = 0
đếnN-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
đếnN-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.
- Trích xuất: Tạo một mảng/vector tạm có kích thước
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ả.
Comments