b. Với các phép toán có một toán hạng, thì hàm toán tử có một
9 CÁC BÀI TOÁN VỀ MA TRẬN VÀ VÉC TƠ
Trong mục này sẽ xét các ma trận thực vuông cấp n và các véc tơ thực cấp n. Chúng được biểu diễn thông qua các kiểu cấu trúc MT và VT:
struct MT {
double a[20][20] ; // Mang a chứa các phần tử ma trận int n ; // Cấp ma trận
} ; struct VT
{
double b[20]; // Mang chua cac phan tu cua vec to int n ; // Cap vec to
} ;
Để xử lý ma trận và véc tơ, chúng ta xây dựng 9 hàm toán tử: ostream& operator<< (ostream& os, const MT& x); // In ma trận ostream& operator<< (ostream& os, const VT& v); // In véc tơ istream& operator>> (istream& is,MT& x); // Nhập ma trận istream& operator>> (istream& is, VT &v); // Nhập véc tơ MT operator+(const MT& x1, const MT& x2); // Cộng 2 ma trận
MT operator-(const MT& x1, const MT& x2); // Trừ 2 ma trận MT operator*(const MT& x1, const MT& x2); // Nhân 2 ma trận
VT operator*(const MT& x, const VT& v); // Nhân ma trận véc tơ
MT operator!(MT x); // Nghịch đảo ma trận Thuật toán cho 8 hàm toán tử đầu tương đối quen thuộc không có gì phải bàn. Để nghịch đảo ma trận có nhiều cách, ở đây chúng ta dùng phương pháp Jordance như sau. Giả sử cần nghịch đảo ma trận x cấp n. Ta dùng thêm ma trận đơn vị y. Sau đó thực hiện đồng thời các phép tính trên cả x và y sao cho x trở thành đơn vị. Kết quả y chính là nghịch đảo của x. Thuật toán được tiến hành trên n bước. Nội dung của bước k (k = 1,...,n) như sau:
Tìm chỉ số r ( k <= r <= n) sao cho
abs(x[r,k]) = max { abs(x[i,k] với i = k,...,n }
Nếu abs(x[r,k]) = 0 thì ma trận không có nghịch đảo và thuật toán kết thúc giữa chừng.
Hoán vị hàng k với hàng r trong cả 2 ma trận x và y.
Chia hàng k của cả x và y cho tg = x[k,k] (mục đích làm cho x[k,k] = 1).
Biến đổi để cột k của x trơ thành véc tơ đơn vị bằng cách làm cho các phần tử x[i,k] = 0 (với i khác k). Muốn vậy ta thực hiện các phép tính sau trên cả x và y:
(hàng i) = (hàng i) - x[i,k]*(hàng k) , với mọi i khác k
Nội dung chương trình là nhập 4 ma trận X, Y, R, S và véc tơ u. Sau đó tính véc tơ v theo công thức:
v = ((X + Y)*(R - S))-1u
Như sẽ thấy trong hàm main() dưới đây, nhờ các hàm toán tử mà câu lệnh tính v được viết gần giống như công thức toán học nêu trên.
/* Chương trình */ #include <conio.h> #include <iostream.h> #include <iomanip.h> #include <math.h> struct MT {
double a[20][20]; // Mang chua cac phan tu ma tran int n ; // Cap ma tran
} ; struct VT
{
double b[20]; // Mang chua cac phan tu cua vec to int n ; // Cap vec to
} ;
ostream& operator<< (ostream& os, const MT& x); ostream& operator<< (ostream& os, const VT& v); istream& operator>> (istream& is,MT& x); istream& operator>> (istream& is, VT &v); MT operator+(const MT& x1, const MT& x2); MT operator-(const MT& x1, const MT& x2); MT operator*(const MT& x1, const MT& x2); VT operator*(const MT& x, const VT& v); MT operator!(MT x); // Tinh ma tran nghich dao ostream& operator<< (ostream& os, const MT& x)
{
os << setprecision(2) << setiosflags(ios::showpoint); for (int i=1 ; i<= x.n ; ++i)
{
os << "\n" ;
for (int j=1; j<=x.n; ++j) os << setw(6) << x.a[i][j] ;
}
os << "\n" ; return os; }
ostream& operator<< (ostream& os, const VT& v) {
os << setprecision(2) << setiosflags(ios::showpoint); for (int i=1 ; i<= v.n ; ++i)
os << setw(6) << v.b[i] ; os << "\n" ;
return os; }
istream& operator>> (istream& is, MT& x) {
cout << " - Cap ma tran: " ; is >> x.n;
cout << "Nhap cac phan tu :\n" ; for (int i=1 ; i<= x.n ; ++i)
for (int j=1; j<=x.n; ++j) {
cout << "PT hang " << i << " cot " << j << " = " ; is >> x.a[i][j] ;
} return is; }
istream& operator>> (istream& is, VT& v) {
cout << " - Cap vec to: " ; is >> v.n;
cout << "Nhap cac phan tu :\n" ; for (int i=1 ; i<= v.n ; ++i)
{
cout << "Phan tu thu " << i << " = " ; is >> v.b[i] ;
} return is; }
MT operator+(const MT& x1, const MT& x2) {
if (x1.n!=x2.n) {
cout << "\nKhong thuc hien duoc phep cong vi 2 MT khong cung cap"; getch(); return x1; } else { MT x; int i, j, n; n = x.n = x1.n ; for (i=1; i<=n; ++i)
for (j=1; j<=n ;++j)
x.a[i][j] = x1.a[i][j] + x2.a[i][j] ; return x;
} }
MT operator-(const MT& x1, const MT& x2) {
{
cout << "\nKhong thuc hien duoc phep tru vi 2 MT khong cung cap"; getch(); return x1; } else { MT x; int i, j, n; n = x.n = x1.n; for (i=1; i<=n; ++i)
for (j=1; j<=n ;++j)
x.a[i][j] = x1.a[i][j] - x2.a[i][j] ; return x;
} }
MT operator*(const MT& x1, const MT& x2) {
if (x1.n!=x2.n) {
cout << "\nKhong thuc hien duoc phep nhan vi 2 MT khong cung cap"; getch(); return x1; } else { MT x; int n, i, j,k; n = x.n = x1.n; for (i=1; i<=n; ++i)
for (j=1; j<=n ;++j) { x.a[i][j] = 0.0 ; for (k=1 ; k<=n; ++k) x.a[i][j] += x1.a[i][k]*x2.a[k][j] ; } return x; } }
VT operator*(const MT& x, const VT& v) {
if (x.n != v.n) {
cout << "\n Cap ma tran khac cap vec to, phep nhan vo nghia"; getch(); return v; } else { VT u; int n; n = u.n = v.n ;
for (int i=1; i <=n ; ++i) {
u.b[i] = 0; for (int j=1; j<=n; ++j) u.b[i] += x.a[i][j]*v.b[j]; } return u; } } MT operator!(MT x) { MT y; int i,j,k,r,n; double tg; n = y.n = x.n ; for (i=1 ; i<=n ; ++i)
for (j=1 ; j<=n ; ++j) if (i==j) y.a[i][j] = 1; else y.a[i][j] = 0; for (k=1; k<=n; ++k) { r=k;
for (i=k+1; i<=n; ++i)
if (abs(x.a[i][k]) > abs(x.a[r][k]) ) r = i; if (abs(x.a[r][k]) < 1.0E-8)
{
cout << "\n Ma tran suy bien, khong co nghich dao" ; getch();
return x; }
/* Hoan vi hang r va hang k */ for (j=1 ; j<=n ; ++j) { tg = x.a[k][j]; x.a[k][j] = x.a[r][j]; x.a[r][j] = tg; tg = y.a[k][j]; y.a[k][j] = y.a[r][j]; y.a[r][j] = tg; }
/* Chia hang k cho a[k,k] */ tg = x.a[k][k] ; for (j=1 ; j<=n ; ++j) { x.a[k][j] /= tg; y.a[k][j] /= tg; }
/* Khu cot k : lam cho a[i,k] = 0 voi i != k */ for (int i=1; i<= n ; ++i)
if (i != k) { tg = x.a[i][k] ; for (j=1 ; j<=n ; ++j) { x.a[i][j] -= tg*x.a[k][j] ;
y.a[i][j] -= tg*y.a[k][j] ; } } } return y; } void main() { MT x,y,r,s; VT u,v; clrscr();
cout <<"\nNhap ma tran X " ; cin >> x; cout <<"\nNhap ma tran Y " ; cin >> y; cout <<"\nNhap ma tran R " ; cin >> r; cout <<"\nNhap ma tran S " ; cin >> s; cout <<"\nNhap vec to u " ; cin >> u; v = !((x+y)*(r-s))*u ;
cout << "\nVec to v = xu " << v ; getch();