Professional Documents
Culture Documents
Giáo trình thực hành này được viết theo giáo trình Lập trình nâng cao nhằm mục đích
làm tài liệu cho sinh viên năm thứ 2 thực hành môn học này. Nội dung của giáo trình
gồm 4 chương thể hiện cơ bản các kỹ thuật lập trình thường gặp đối với sinh viên.
Chương 1. Kỹ thuật lập trình đệ quy.
Chương 2. Sắp xếp.
Chương 3. Đại số ma trận.
Chương 4. Một số thuật giải trên đồ thị.
Chương 1 thể hiện một số kỹ thuật lập trình làm nền tảng cho các chương sau. Đối với
đệ quy phi tuyến chủ yếu ta sử dụng kỹ thuật tìm kiếm theo chiều sâu. Kỹ thuật này
được áp dụng trong chương 4 để tìm đường đi trên đồ thị. Tuy nhiên, ở đây ta chưa
trình bài kỹ thuật duyệt theo chiều sâu bằng cách khử đệ quy. Kỹ thuật này sẽ được
trình bài trong giáo trình Lý thuyết đồ thị và thuật giải.
Chương 2 thể hiện một số thuật toán sắp xếp nhằm giúp sinh viên so sánh và đánh giá
thuật toán sắp xếp nào sẽ tốt hơn.
Chương 3 thể hiện phương pháp giải hệ phương trình tuyến tính bằng phương pháp
phân rã ma trận bằng thuật toán Crout.
Chương 4 thể hiện một số thuật giải tìm đường đi cơ bản trên đồ thị áp dụng kỹ thuật
đánh dấu đỉnh, đánh dấu cạnh và kỹ thuật tham ăn.
Vì thời gian phân bố giảng dạy theo chương trình khung và nội dung của môn học này
nên giáo trình không tránh khỏi những khiếm khuyết. Rất mong nhận được sự góp ý
của tất cả các bạn quan tâm đến giáo trình này.
Viết chương trình tìm phần tử Fibonacci thứ n được định nghĩa đệ quy như sau:
1 ,n 0 n 1
F ( n)
F n 1 F n 2 , n 1
Cài đặt:
#include <conio.h>
#include <iostream.h>
/*Ham tra ve so nguyen tinh gia tri Fibonacci thu n*/
int F(int n) {
if(n==0 || n==1)
return 1;
else
return F(n-1) + F(n-2);
}
/*Chuong trinh chinh*/
void main() {
clrscr();
int n;
cout<<"Nhap vao gia tri cua n = ";
cin>>n;
cout<<"F("<<n<<") = "<<F(n);
getch();
}
Viết chương trình tính X n với X là số thực được xác định như sau:
1 ,n 0
Xn n 1
X * X ,n 0
Cài đặt:
#include <conio.h>
#include <iostream.h>
/*Ham tra ve so thuc tinh gia tri X^n*/
float Power(float X, int n) {
if(n==0)
return 1;
else
Trang 1
return X*Power(X,n-1);
}
/*Chuong trinh chinh*/
void main() {
clrscr();
int n;
float X;
cout<<"Nhap vao gia tri cua n = ";
cin>>n;
cout<<"Nhap vao gia tri cua X = ";
cin>>X;
cout<<X<<"^"<<n<<" = "<<Power(X,n);
getch();
}
Bài tập 3. Thuật toán Euclide tìm ước chung lớn nhất
Viết chương trình tìm ước chung lớn nhất của 2 số nguyên dương a, b bằng thuật toán
Euclide được định nghĩa đệ quy như sau:
a , a b
UCLN (a, b ) UCLN (a, b a ) , b a
UCLN (a b, b ), a b
Cài đặt:
#include <conio.h>
#include <iostream.h>
int UCLN(int a, int b) {
if(a==b)
return a;
else if(a>b)
return UCLN(a-b,b);
else
return UCLN(a,b-a);
}
void main() {
clrscr();
int a,b;
cout<<"Nhap a = ";
cin>>a;
cout<<"Nhap b = ";
cin>>b;
cout<<"Uoc chung lon nhat cua "<<a<<" va "<<b<<" la "<<UCLN(a,b);
getch();
}
Trang 2
Bài tập 4. Tìm ước chung lớn nhất của n số nguyên
Viết chương trình tìm ước chung lớn nhất của n số nguyên dương a0 ,..., an 1 được định
nghĩa đệ quy như sau:
a0 ,n 1
UC a 0 ,..., a n1 , n
UCLN a n1 ,UC a0 ,..., a n 2 , n 1 , n 1
Cài đặt:
#include <conio.h>
#include <iostream.h>
/*Ham tra ve uoc chung lon nhat cua a va b*/
int UCLN(int a, int b) {
if(a==b)
return a;
else if(a>b)
return UCLN(a-b,b);
else
return UCLN(a,b-a);
}
/*Ham tra ve uoc chung lon nhat cua n phan tu duoc luu tru trong mang 1 chieu a*/
int UC(int a[], int n) {
if(n==1)
return a[0];
else
return UCLN(a[n-1],UC(a,n-1));
}
void main() {
clrscr();
int *a,n;
cout<<"Nhap n = ";
cin>>n;
a = new int[n];
cout<<"Nhap vao "<<n<<" phan tu\n";
for(int i=0; i<n ; i++){
cout<<"a["<<i<<"] = ";
cin>>a[i];
}
cout<<"UCLN cua "<<n<<" phan tu vua nhap la "<<UC(a,n);
getch();
}
Trang 3
Bài tập 5. Tính n giai thừa
Viết chương trình tính n! được định nghĩa đệ quy như sau:
1 ,n 0
n !
n * n 1! , n 1
Cài đặt:
#include <conio.h>
#include <iostream.h>
/*Ham tra ve so nguyen tinh n! (Factorial)*/
long int Fac(int n) {
if(n==0)
return 1;
else
return n*Fac(n-1);
}
/*Chuong trinh chinh*/
void main() {
clrscr();
int n;
cout<<"Nhap vao gia tri cua n = ";
cin>>n;
cout<<n<<"! = "<<Fac(n);
getch();
}
Viết chương trình tính Cnk được xác định như sau:
1 ,k 0 n k
C nk k 1 k
C n 1 C n 1
Cài đặt:
#include <conio.h>
#include <iostream.h>
/*C(n,k)=C(n-1,k-1)+c(n-1,k) dk: 0<k<n; c(n,0)=c(n,n)=1*/
long int C(int n, int k) {
if (n==k||k==0)
return 1;
else
return C(n-1,k-1)+C(n-1,k);
Trang 4
}
/*Chuong trinh chinh*/
void main() {
clrscr();
int n,k;
cout<<"n = ";
cin>>n;
cout<<"k = ";
cin>>k;
cout<<"C("<<n<<","<<k<<") = "<<C(n,k);
getch();
}
Viết chương trình tính tổng n phần tử a0 ,..., a n 1 được định nghĩa đệ quy như sau:
a 0 ,n 1
S a 0 ,..., a n1 , n
a n 1 S a 0 ,..., a n 2 , n 1 , n 1
Cài đặt:
#include <conio.h>
#include <iostream.h>
/*Ham tra ve so nguyen tinh tong n phan tu trong mang a*/
long int S(int a[], int n) {
if(n==1)
return a[0];
else
return a[n-1]+S(a,n-1);
}
/*Chuong trinh chinh*/
void main() {
clrscr();
int *a,n;
cout<<"n = ";
cin>>n;
a = new int[n];
cout<<"Nhap vao "<<n<<" phan tu\n";
for(int i=0; i<n ; i++){
cout<<"a["<<i<<"] = ";
cin>>a[i];
}
cout<<"Tong "<<n<<" phan tu trong mang a la "<<S(a,n);
getch();
}
Trang 5
Bài tập 8. Đệ quy hỗ tương
X 0 1
Y 1
0
X n X n1 Yn1
Yn 2 X n 1Yn1
Cài đặt:
#include <conio.h>
#include <iostream.h>
long int Y(int n);
long int X(int n) {
if(n==0)
return 1;
else
return X(n-1) + Y(n-1);
}
long int Y(int n) {
if(n==0)
return 1;
else
return 2*X(n-1)*Y(n-1);
}
/*Chuong trinh chinh*/
void main() {
clrscr();
int n;
cout<<"n = ";
cin>>n;
cout<<"X("<<n<<") = "<<X(n);
cout<<"Y("<<n<<") = "<<Y(n);
getch();
}
Trang 6
Bài tập 9. Tích n phần tử trong danh sách
Viết chương trình tính tích n phần tử a0 ,..., a n 1 được định nghĩa đệ quy như sau:
a 0 ,n 1
S a 0 ,..., a n1 , n
a n1 S a 0 ,..., a n 2 , n 1 , n 1
Cài đặt:
#include <conio.h>
#include <iostream.h>
/*Ham tra ve so nguyen tinh tich n phan tu trong mang a*/
long int S(int a[], int n) {
if(n==1)
return a[0];
else
return a[n-1]*S(a,n-1);
}
/*Chuong trinh chinh*/
void main() {
clrscr();
int *a,n;
cout<<"n = ";
cin>>n;
a = new int[n];
cout<<"Nhap vao "<<n<<" phan tu\n";
for(int i=0; i<n ; i++){
cout<<"a["<<i<<"] = ";
cin>>a[i];
}
cout<<"Tong "<<n<<" phan tu trong mang A la "<<S(a,n);
getch();
}
Trang 7
Bài tập 10. Đếm số lần xuất hiện của phần tử x trong danh sách
Viết chương trình đếm số lần xuất hiện của số nguyên x trong danh sách
A a 0 ,..., a n 1 với n phần tử. Thuật toán đệ quy được thể hiện như sau:
0 ,n 0
Find A, n, x 1 Find A, n 1, x , n 0 a n x
Find A, n 1, x , n 0 an x
Cài đặt:
#include <conio.h>
#include <iostream.h>
/*Ham tra ve so lan xuat hien cua x trong danh sach A*/
int Find(int a[], int n, int x) {
if(n==0)
return 0;
else
if(a[n-1]==x)
return 1+Find(a,n-1,x);
else
return Find(a,n-1,x);
}
/*Chuong trinh chinh*/
void main() {
clrscr();
int *a,n,x;
cout<<"n = ";
cin>>n;
a = new int[n];
cout<<"Nhap vao danh sach "<<n<<" phan tu\n";
for(int i=0; i<n ; i++){
cout<<"a["<<i<<"] = ";
cin>>a[i];
}
cout<<"x = ";
cin>>x;
cout<<"So lan xuat hien cua "<<x<<"trong danh sach la "<<Find(a,n,x);
getch();
}
Trang 8
Bài tập 11. Tháp Hà Nội
Mô tả bài toán: chuyển n đĩa từ cột 1 sang cột 2 lấy cột 3 làm trung gian. Thứ tự các
đĩa được sắp xếp từ nhỏ đến lớn (đĩa lớn nắm phía dưới).
Ví dụ: n = 3 ta có các bước chuyển 12, 13, 23, 12, 31, 32, 12.
Cài đặt:
#include "conio.h"
#include "iostream.h"
/*Thap Ha Noi*/
void Move(int n, int a, int b) {
if (n==1)
cout<<a<<"-->"<<b<<"\n";
else {
Move(n-1,a,6-a-b);
Move(1,a,b);
Move(n-1,6-a-b,b);
}
}
/*Chuong trinh chinh*/
void main() {
clrscr();
int n;
cout<<"Nhap n =";
cin>>n;
Move(n,1,2); //chuyen n dia tu cot 1 sang cot 2 lay cot 3 lam trung gian
getch();
}
Trang 9
Bài tập 12. Liệt kê tất cả dãy nhị phân độ dài k
Chỉnh hợp lặp chập k của n phần tử là một nhóm có thứ tự gồm k phần tử lấy từ n
phần tử đã cho, trong đó mỗi phần tử có thể có mặt 1, 2, …, k lần trong nhóm tạo
thành.
Phương pháp: ta liệt kê tất cả chỉnh hợp có lặp chập k của hai phần tử 0 và 1. Khi đó
ta sẽ có tất cả dãy nhị phân có độ dài k.
Ví dụ: minh họa dạng cây với k = 3.
Cài đặt:
#include "conio.h"
#include "iostream.h"
#define max 20
int Luu[max];
int k;
/*Xuat ket qua ra man hinh*/
void Out() {
cout<<endl;
for(int i = 0; i<k; i++)
cout<<Luu[i];
}
/*Day nhi phan do dai n*/
void Try(int i) {
if(i==k)
Out();
else {
for(int j = 0; j<=1; j++) {
Luu[i] = j;
Try(i+1);
Luu[i]=0;
}
Trang 10
}
}
/*Chuong trinh chinh*/
void main() {
clrscr();
cout<<"Nhap n = ";
cin>>k;
cout<<"Day nhi phan do dai k.\n";
Try(0);
getch();
}
void Try(int i) {
for(int j = 0; j<=1; j++) {
Luu[i] = j;
if(i==k-1)
Out();
else
Try(i+1);
}
}
Trang 11
Bài tập 13. Chỉnh hợp không lặp chập k của n phần tử
Chỉnh hợp chập k của n phần tử ( k n ) là một nhóm có thứ tự gồm k phần tử khác
nhau được chọn từ n phần tử đã cho.
Phương pháp: liệt kê dãy có độ dài k và các phần tử trong dãy được lấy từ tập hợp {0,
1, … , n-1} các phần tử được đưa vào dãy không được phép trùng nhau.
Ví dụ: n = 3 và k = 2 ta sẽ có các dãy con {0,1}, {0,2}, {1,0}, {1,2}, {2,0} và {2,1}.
Cài đặt:
#include "conio.h"
#include "iostream.h"
#define max 20
char DanhDau[max];
int Luu[max];
int n,k;
/*Khoi tao cac bien*/
void Init() {
cout<<"Nhap n = ";
cin>>n;
cout<<"Nhap k = ";
cin>>k;
//khoi tao tat ca cac dinh chua duoc chon
for(int i = 0; i<k; i++)
DanhDau[i] = 0;
}
/*Xuat ket qua ra man hinh*/
void Out() {
cout<<endl;
for(int i = 0; i<k; i++)
cout<<Luu[i]<<" ";
}
/*Chinh hop khong lap chap k*/
void Try(int i) {
if(i==k)
Out();
else {
for(int j = 0; j<n; j++)
if(DanhDau[j] == 0) { //neu dinh j chua duoc chon
DanhDau[j] = 1; //chon dinh j
Luu[i] = j; //luu lai gia tri j
Try(i+1); //tim phan tu tiep theo
DanhDau[j] = 0; //phuc hoi dinh j
Trang 12
}
}
}
/*Chuong trinh chinh*/
void main() {
clrscr();
cout<<"Chinh hop khong lap n chap k";
Init();
Try(0);
getch();
}
void Try(int i) {
for(int j = 0; j<n; j++)
if(DanhDau[j]==0) {
Luu[i] = j;
if(i==n-1)
Out();
else {
DanhDau[j] = 1;
Try(i+1);
DanhDau[j] = 0;
}
}
}
Trang 13
Bài tập 14. Hoán vị mảng số nguyên có n phần tử
Phương pháp: tương tự phương pháp làm bài tập 13 nhưng ở đây ta thay tập hợp {0, 1,
… , n-1} là tập hợp giá trị n phần tử của mảng và độ dài của dãy là n.
Ví dụ: n = 3 và A = {-1,0,1} ta sẽ có các dãy con tương ứng là {-1,0}, {-1,1}, {0,-1},
{0,1}, {1,-1} và {1,0}.
Cài đặt:
#include "conio.h"
#include "iostream.h"
#define max 20
char DanhDau[max]; //mang danh dau dinh duoc chon
int Luu[max], A[max], n;
/*Khoi tao cac bien*/
void Init() {
cout<<"Nhap n = ";
cin>>n;
for(int i = 0; i<n; i++) {
/*Danh dau vi tri i chua chon*/
DanhDau[i] = 0;
cout<<"A["<<i<<"] = ";
cin>>A[i];
}
}
/*Xuat ket qua ra man hinh*/
void Out() {
cout<<endl;
for(int i = 0; i<n; i++)
cout<<Luu[i]<<" ";
}
/*Hoan vi mang n phan tu*/
void Try(int i) {
if(i==n)
Out();
else {
for(int j = 0; j<n; j++)
if(DanhDau[j] == 0) { //neu dinh j chua duoc chon
DanhDau[j] = 1; //chon dinh j
Luu[i] = A[j]; //luu lai gia tri dinh duoc chon
Try(i+1); //tim dinh tiep theo
DanhDau[j] = 0; //phuc hoi dinh j
}
}
Trang 14
}
/*Chuong trinh chinh*/
void main() {
clrscr();
Init();
cout<<"Hoan vi cac phan tu trong mang A";
Try(0);
getch();
}
void Try(int i) {
for(int j = 0; j<n; j++)
if(DanhDau[j]==0) {
Luu[i] = A[j];
if(i==n-1)
Out();
else {
DanhDau[j] = 1;
Try(i+1);
DanhDau[j] = 0;
}
}
}
Trang 15
Bài tập 15. Đặt n quân hậu trên bàn cờ vua
Mô tả bài toán: liệt kê tất cả phương án đặt n quân hậu trên bàn cờ vua cấp n n sao
cho n quân hậu không được phép ăn nhau.
Ví dụ: cho bàn cờ vua cấp 8 8 . Dưới đây là 1 phương án đặt quân hậu:
Cài đặt:
#include "conio.h"
#include "iostream.h"
#define max 20
char a[max]; //danh dau cot
char b[2*max-1]; //danh dau huong Dong-Bac
char c[2*max-1]; //danh dau huong Tay-Bac
int Luu[max]; //luu ket qua tim duoc
int n;
/*Khoi tao cac bien*/
void Init() {
cout<<"Nhap n = ";
cin>>n;
//tat ca cac cot chua duoc chon
for(int i = 0; i<n; i++)
a[i] = 0;
//tat ca cac huong chua duoc chon
for( i = 0; i<2*n-1; i++) {
b[i] = 0;
c[i] = 0;
}
}
/*Xuat ket qua ra man hinh*/
void Out() {
Trang 16
cout<<endl;
for(int i = 0; i<n; i++)
cout<<"("<<i+1<<","<<Luu[i]+1<<") ";
}
/*Chinh hop khong lap chap k*/
void Try(int i) {
if(i==n)
Out();
else {
for(int j = 0; j<n; j++)
if(a[j] == 0 && b[i+j] == 0 && c[i-j+n] == 0) {
a[j] = 1; //danh dau cot j
b[i+j] = 1; //danh dau huong Dong-Bac thu i+j
c[i-j+n] = 1; //danh dau huong tay-Bac thu j-i+n
Luu[i] = j; //luu vi tri dat hau (i,j)
Try(i+1); //tim vi tri dat hau tiep theo
a[j] = 0; //phuc hoi cot j
b[i+j] = 0; //phuc hoi huong Dong-Bac thu i+j
c[i-j+n] = 0; //phuc hoi huong tay-Bac thu j-i+n
}
}
}
/*Chuong trinh chinh*/
void main() {
clrscr();
Init();
cout<<"Dat Hau";
Try(0);
getch();
}
Trang 17
Bài tập 16. Mã đi tuần
Mô tả bài toán: đặt quân mã tại ô có vị trí (x,y) trên bàn cờ vua cấp n n . Hãy liệt kê
tất cả các phương án quân mã xuất phát tại vị trí (x,y) có thể nhảy đến tất cả các ô khác
trên bàn cờ với điều kiện mỗi ô quân mã chỉ được phép đi qua đúng 1 lần.
Ví dụ: cho bàn cờ vua cấp 8 8 . Ta có 2 phương án đặt quân mã như sau:
Cài đặt:
#include "iostream.h"
#include "conio.h"
#define max 10
int A[max][max]; //Mang danh dau
int B[max][max]; //Mang luu duong di
int X[8]={-1,-2,-2,-1,1,2,2,1};
int Y[8]={-2,-1,1,2,2,1,-1,-2};
int n, x, y, Dem=0;
//Khoi tao
void Init() {
cout<<"Nhap n = ";
cin>>n;
cout<<"Nhap x = ";
cin>>x;
cout<<"Nhap y = ";
cin>>y;
for(int i = 0; i<n; i++)
for(int j = 0; j<n; j++)
A[i][j] = 0; //tat ca cac o chua duoc danh dau
B[x][y] = 1; //duong di dau tien
A[x][y] = 1; //danh dau o duoc chon
}
//Xuat ket qua ra man hinh
Trang 18
void Out() {
Dem++;
for(int i = 0; i<n; i++) {
for(int j = 0; j<n; j++) {
printf("%3d",B[i][j]);
}
cout<<endl;
}
cout<<endl;
}
//Tim duong di
void Try(int i) {
if(i > n*n)
Out();
else {
for(int j = 0; j<8; j++) {
int x1 = x + X[j];
int y1 = y + Y[j];
if(x1>=0 && x1<n && y1>=0 && y1<n && A[x1][y1]==0){
A[x1][y1] = 1; //danh dau o (i,j)
B[x1][y1] = i; //luu lai duong di
x = x1; //lay toa do x moi
y = y1; //lay toa do y moi
Try(i+1); //tim duong di tiep theo
A[x1][y1] = 0; //phuc hoi o (i,j)
B[x1][y1] = 0; //xem nhu o chua di qua
x = x1 - X[j]; //phuc hoi dinh x
y = y1 - Y[j]; //phuc hoi dinh y
}
}
}
}
//chuong trinh chinh
void main() {
clrscr();
Init();
Try(2);
if (Dem==0)
cout<<"Khong co duong di";
else
cout<<"So phuong an tim duoc"<<Dem;
getch();
}
Trang 19
CHƯƠNG 2. SẮP XẾP
Sau 9 bước lặp ta thu được dãy đã được sắp xếp: {2, 3, 3, 4, 6, 6, 7, 9, 10, 15}.
Cài đặt:
#include <iostream.h>
#include <conio.h>
#define max 100
//nhap mang
void NhapMang(int A[],int n) {
for(int i=0; i<n; i++) {
cout<<"nhap Phan tu thu A["<<i<<"] =";
cin>>A[i];
}
}
//xuat mang
void XuatMang(int A[],int n) {
cout<<endl;
for(int i=0; i<n; i++)
cout<<A[i]<<"\t";
}
Trang 20
//hoan vi 2 phan tu
void Swap(int &a,int &b) {
int temp = a;
a = b;
b = temp;
}
//sap xep cac phan tu
void BubbleSort(int A[],int n) {
for(int i = 0; i < n-1; i++)
for(int j = n-1; j > i; j--)
if(A[j]<A[j-1])
Swap(A[j-1],A[j]);
}
//chuong trinh chinh
void main() {
int A[max],n;
clrscr();
cout<<"Nhap so phan tu:";
cin>>n;
NhapMang(A,n);
cout<<"\nMang vua nhap la:";
XuatMang(A,n);
cout<<endl;
BubbleSort(A,n);
cout<<"\nMang vua sap xep la:";
XuatMang(A,n);
getch();
}
Chúng ta có thể cài đặt thủ tục Bubble Sort như sau để xem kết quả từng bước chạy:
#include <iostream.h>
#include <conio.h>
#define max 100
void NhapMang(int A[],int n) {
for(int i=0; i<n; i++) {
cout<<"nhap Phan tu thu A["<<i<<"] =";
cin>>A[i];
}
}
void XuatMang(int A[],int n, int k) {
cout<<endl;
for(int i=0; i<n; i++)
if(i<k)
Trang 21
cout<<"\t";
else
cout<<A[i]<<"\t";
}
void Swap(int &a,int &b) {
int temp = a;
a = b;
b = temp;
}
void BubbleSort(int A[],int n) {
for(int i=0; i<n-1; i++){
for(int j=n-1; j>i; j--)
if(A[j]<A[j-1])
Swap(A[j-1],A[j]);
XuatMang(A,n,i);
}
}
void main() {
int A[max],n;
clrscr();
cout<<"Nhap so phan tu:";
cin>>n;
NhapMang(A,n);
cout<<"\nThuat toan Bubble Sort";
XuatMang(A,n,0);
BubbleSort(A,n);
XuatMang(A,n,0);
getch();
}
Trang 22
Bài tập 2. Thuật toán Selection Sort
Sau 9 bước lặp ta thu được dãy đã được sắp xếp: {2, 3, 4, 5, 6, 6, 7, 7, 8, 9}.
Cài đặt:
#include <iostream.h>
#include <conio.h>
#define max 100
//nhap mang
void NhapMang(int A[],int n) {
for(int i=0; i<n; i++) {
cout<<"nhap Phan tu thu A["<<i<<"] =";
cin>>A[i];
}
}
//xuat mang
void XuatMang(int A[],int n) {
cout<<endl;
for(int i=0; i<n; i++)
cout<<A[i]<<"\t";
}
//hoan vi 2 phan tu
void Swap(int &a,int &b) {
int temp = a;
a = b;
b = temp;
Trang 23
}
//thuat toan Selection Sort
void SelectionSort(int A[],int n) {
int min; // chi so phan tu nho nhat trong day hien hanh
for(int i=0; i<n-1; i++) {
min = i;
for(int j=i+1; j<n; j++)
if(A[min]>A[j])
min = j; //ghi nhan vi tri phan tu nho nhat
if(min != i)
Swap(A[i],A[min]);
}
}
//chuong trinh chinh
void main() {
int A[max],n;
clrscr();
cout<<"Nhap so phan tu:";
cin>>n;
NhapMang(A,n);
cout<<"\nMang vua nhap la:";
XuatMang(A,n);
cout<<endl;
SelectionSort (A,n);
cout<<"\nMang vua sap xep la:";
XuatMang(A,n);
getch();
}
Chúng ta có thể cài đặt thủ tục Selection Sort như sau để xem kết quả từng bước chạy:
#include <iostream.h>
#include <conio.h>
#define max 100
void NhapMang(int A[],int n) {
for(int i=0; i<n; i++) {
cout<<"nhap Phan tu thu A["<<i<<"] =";
cin>>A[i];
}
}
void XuatMang(int A[],int n, int k) {
cout<<endl;
for(int i=0; i<n; i++)
if(i<k)
Trang 24
cout<<"\t";
else
cout<<A[i]<<"\t";
}
void Swap(int &a,int &b) {
int temp = a;
a = b;
b = temp;
}
void SelectionSort(int A[],int n) {
int min;
for(int i=0;i<n-1;i++){
min = i;
for(int j=i+1;j<n;j++)
if(A[min]>A[j])
min = j;
if(min!=i)
Swap(A[i],A[min]);
XuatMang(A,n,i);
}
}
void main() {
int A[max],n;
clrscr();
cout<<"Nhap so phan tu:";
cin>>n;
NhapMang(A,n);
cout<<"\nThuat toan Selection Sort";
XuatMang(A,n,0);
SelectionSort(A,n);
XuatMang(A,n,0);
getch();
}
Trang 25
Bài tập 3. Thuật toán Insertion Sort
Ý tưởng thuật toán: xét dãy n phần tử a 0 , a1 ,..., a n1 .
Xem dãy gồm 1 phần tử a0 là dãy có thứ tự.
Thêm a1 vào dãy có thứ tự a0 sao cho dãy mới a0, a1 là dãy có thứ tự. Nếu a1 < a0 ta
hoán vị a1 với a0.
Thêm a2 vào dãy có thứ tự a0, a1 sao cho dãy mới a0, a1, a2 là dãy có thứ tự.
Tiếp tục như thế đến n – 1 bước ta sẽ có dãy có thứ tự a 0 , a1 ,..., a n1 .
Ví dụ: sử dụng thuật toán Insertion Sort sắp xếp dãy {3,7,22,3,1,5,8,4,3,9} theo thứ tự
tăng dần.
Cài đặt:
#include <iostream.h>
#include <conio.h>
#define max 100
//nhap mang
void NhapMang(int A[],int n) {
for(int i=0; i<n; i++) {
cout<<"nhap Phan tu thu A["<<i<<"] =";
cin>>A[i];
}
}
//xuat mang
void XuatMang(int A[],int n) {
cout<<endl;
for(int i=0; i<n; i++)
cout<<A[i]<<"\t";
}
//hoan vi 2 phan tu
void Swap(int &a,int &b) {
int temp = a;
a = b;
b = temp;
Trang 26
}
//thu tuc Insertion Sort
void InsertionSort(int A[],int n) {
for(int i=1; i<n; i++)
for(int j=i; j>0; j--)
if(A[j]<A[j-1])
Swap(A[j],A[j-1]);
}
//chuong trinh chinh
void main() {
int A[max],n;
clrscr();
cout<<"Nhap so phan tu:";
cin>>n;
NhapMang(A,n);
cout<<"\nMang vua nhap la:";
XuatMang(A,n);
cout<<endl;
InsertionSort (A,n);
cout<<"\nMang vua sap xep la:";
XuatMang(A,n);
getch();
}
Chúng ta có thể cài đặt thủ tục Insertion Sort như sau để xem kết quả từng bước chạy:
Trang 27
Bài tập 4. Thuật toán Quick Sort
Bước 2: Phân vùng. Những phần tử nhỏ hơn khóa thì nằm bên trái của khóa, những
phần tử lớn hơn khóa thì nằm bên phải của khóa và những phần tử bằng khóa
có thể nằm bất cứ chỗ nào trên dãy.
Bước 3: sắp xếp cho cả hai phân vùng mới bên trái và bên phải.
Mô tả hoạt động của thuật toán Quick Sort:
Cài đặt:
#include <iostream.h>
#include <conio.h>
#define max 100
void NhapMang(int A[],int n) {
for(int i=0; i<n; i++) {
cout<<"nhap Phan tu thu A["<<i<<"] =";
cin>>A[i];
}
}
void XuatMang(int A[],int n) {
cout<<endl;
Trang 28
for(int i=0; i<n; i++)
cout<<A[i]<<"\t";
}
void Swap(int &a,int &b) {
int temp = a;
a = b;
b = temp;
}
void QuickSort(int A[], int Left, int Right) {
int i = Left, j = Right;
int pivot = A[(Left + Right) / 2];
/* partition */
while (i <= j) {
while (A[i] < pivot)
i++;
while (A[j] > pivot)
j--;
if (i <= j) {
Swap(A[i],A[j]);
i++;
j--;
}
}
/* recursion */
if (Left < j)
QuickSort(A, Left, j);
if (i < Right)
QuickSort(A, i, Right);
}
void main() {
int A[max], n;
clrscr();
cout<<"Nhap so phan tu:";
cin>>n;
NhapMang(A,n);
cout<<"\nMang vua nhap la:";
XuatMang(A,n);
cout<<"\nSap xep theo Quick Sort:";
QuickSort(A,0,n-1);
XuatMang(A,n);
getch();
}
Trang 29
Bài tập 5. Thuật toán Heap Sort
Ta xem danh sách n phần tử a0 , a1 ,..., an1 là cây nhị phân. Cây nhị phân này được xác
định như sau: tại nút thứ i tương ứng với chỉ số thứ i của mảng có con trái là nút
2*(i+1)-1 và con phải 2*(i+1) nếu 2*(i+1)-1 và 2*(i+1) nhỏ hơn n. Thuật toán được
mô tả như sau:
- Xây dựng Heap sao cho với mọi nút cha đều có giá trị lớn hơn nút con. Khi đó nút
gốc là nút có giá trị lớn nhất.
- Hoán vị nút gốc với nút thứ n – 1 và xây dựng lại Heap mới với n – 2 nút và tiếp
tục hoán vị nút gốc với nút lá cuối của cây mới sau n – 2 bước ta sẽ thu được danh
sách được sắp xếp theo thứ tự.
Ví dụ: xét danh sách trước khi sắp xếp
0 1 2 3 4 5 6 7
11 3 5 4 9 15 19 7
Danh sách trên được thể hiện bằng cây theo thuật toán Heap Sort như sau:
Trang 30
Trang 31
Sau 7 bước ta thu được danh sách đã được sắp xếp
0 1 2 3 4 5 6 7
3 4 5 7 9 11 15 19
Cài đặt:
#include <iostream.h>
#include <conio.h>
#define max 100
void NhapMang(int A[],int n) {
for(int i=0; i<n; i++) {
cout<<"nhap Phan tu thu A["<<i<<"] =";
cin>>A[i];
}
}
void XuatMang(int A[],int n) {
cout<<endl;
for(int i=0; i<n; i++)
cout<<A[i]<<"\t";
}
void Swap(int &a,int &b) {
int temp = a;
a = b;
b = temp;
}
//hoan vi nut cha thu i phai lon hon nut con
void Heapify(int A[],int n, int i) {
int Left = 2*(i+1)-1;
int Right = 2*(i+1);
int Largest;
if(Left<n && A[Left]>A[i])
Largest = Left;
else
Largest = i;
if(Right<n && A[Right]>A[Largest])
Trang 32
Largest = Right;
if(i!=Largest) {
Swap(A[i],A[Largest]);
Heapify(A,n,Largest);
}
}
//xay dung Heap sao cho moi nut cha luon lon hon nut con tren cay
void BuildHeap(int A[], int n) {
for(int i = n/2-1; i>=0; i--)
Heapify(A,n,i);
}
void HeapSort(int A[], int n) {
BuildHeap(A,n);
for(int i = n-1; i>0; i--){
Swap(A[0],A[i]);
Heapify(A,i,0);
}
}
void main() {
int A[max], n;
clrscr();
cout<<"Nhap so phan tu:";
cin>>n;
NhapMang(A,n);
cout<<"\nMang vua nhap la:";
XuatMang(A,n);
cout<<"\nSap xep theo Heap Sort:";
HeapSort(A,n);
XuatMang(A,n);
getch();
}
Trang 33
Bài tập 6. Thuật toán Merge Sort
Mô tả bài toán: cho 2 danh sách A và B lần lượt có m và n phần tử đã sắp xếp theo thứ
tự. Bài toán đặt ra trộn 2 danh sách A và B với nhau thành danh sách C cũng là một
danh sách có thứ tự.
Thuật toán:
Bước 1: khởi tạo ba chỉ số chạy trong vòng lặp i = 0, j = 0, k = 0 tương ứng cho ba
mảng A, B và C.
Bước 2: tại mỗi bước nếu cả hai chỉ số (i<m và j<n) ta chọn min(A[i],B[j]) và lưu nó
vào trong C[k]. Chuyển sang Bước 4.
Bước 3: tăng giá trị k lên 1 và quay về Bước 2.
Bước 4: sao chép tất cả các giá trị còn lại từ các danh sách mà chỉ số còn vi phạm (tức
i<m hoặc j<m) vào trong mảng C.
Cài đặt:
#include <iostream.h>
#include <conio.h>
#define max 100
void NhapMang(int A[],int n) {
for(int i=0; i<n; i++) {
cout<<"Phan tu "<<i<<" = ";
cin>>A[i];
}
}
void XuatMang(int A[],int n) {
cout<<endl;
for(int i=0; i<n; i++)
cout<<A[i]<<"\t";
}
void MergeSort(int m, int n, int &k, int A[], int B[], int C[]) {
int i = 0, j = 0;
k = 0;
while (i < m && j < n) {
if (A[i] <= B[j]) {
C[k] = A[i];
i++;
} else {
C[k] = B[j];
j++;
}
Trang 34
k++;
}
if (i < m) {
for (int p = i; p < m; p++) {
C[k] = A[p];
k++;
}
} else {
for (int p = j; p < n; p++) {
C[k] = B[p];
k++;
}
}
}
void main() {
int A[max],B[max],C[max],n,m,k;
clrscr();
cout<<"n = ";
cin>>n;
cout<<"m = ";
cin>>m;
cout<<"Nhap danh sach co thu tu A:\n";
NhapMang(A,m);
cout<<"Nhap danh sach co thu tu B:\n";
NhapMang(B,n);
cout<<"\nSap xep tron 2 mang A, B\n";
MergeSort(m,n,k,A,B,C);
XuatMang(C,k);
getch();
}
Trang 35
CHƯƠNG 3. ĐẠI SỐ MA TRẬN
Phương pháp: ta tổ chức mảng hai chiều lưu trữ các phần tử trong ma trận.
Cài đặt:
#include "conio.h"
#include "iostream.h"
#define max 100
/*Nhap ma tran he so*/
void NhapMaTran(float A[max][max], int m, int n) {
for(int i = 0; i<m; i++)
for(int j = 0; j<n; j++) {
cout<<"a["<<i<<"]["<<j<<"] = ";
cin>>A[i][j];
}
}
/*Xuat ma tran*/
void XuatMaTran(float A[max][max], int m, int n) {
for(int i=0 ; i<m; i++){
cout<<endl;
for(int j=0 ; j<n; j++)
cout<<A[i][j]<<"\t";
}
}
/*Chuong trinh chinh*/
void main() {
int m, n;
float A[max][max];
clrscr();
cout<<"Nhap so dong m = ";
cin>>m;
cout<<"Nhap so cot n = ";
cin>>n;
cout<<"\nNhap ma tran A cap "<<m<<"x"<<n<<endl;
NhapMaTran(A,m,n);
cout<<"\nXuat ma tran A";
XuatMaTran(A,m,n);
getch();
}
Trang 36
Bài tập 2. Một số phép toán trên ma trận
Cộng ma hai ma trận
Cho A aij và B bij là hai ma trận cùng cấp m n . Khi đó C A B cũng là
ma trận cấp m n và được xác định bởi cij aij bij ,1 i m,1 j n .
i 1, ..., m và k 1, ..., p .
Cài đặt:
#include "conio.h"
#include "iostream.h"
#define max 100
/*Nhap ma tran he so*/
void NhapMaTran(float A[max][max], int m, int n, char ch) {
for(int i = 0; i<m; i++)
for(int j = 0; j<n; j++) {
cout<<ch<<"["<<i<<"]["<<j<<"] = ";
cin>>A[i][j];
}
}
/*Xuat ma tran*/
void XuatMaTran(float A[max][max], int m, int n) {
for(int i=0 ; i<m; i++){
cout<<endl;
for(int j=0 ; j<n; j++)
cout<<A[i][j]<<"\t";
}
}
/*C = A+B*/
void CongMaTran(float A[max][max], float B[max][max], float C[max][max], int m, int n) {
for(int i = 0; i<m; i++)
for(int j = 0; j<n; j++)
C[i][j] = A[i][j]+B[i][j];
}
/*A cap mxn * B cap nxp = C cap mxp*/
void NhanMaTran(float A[max][max],float B[max][max] float C[max][max],int m,int n,int p)
{
Trang 37
for(int i = 0; i<m; i++)
for(int k = 0; k<p; k++) {
C[i][k]=0;
for(int j = 0; j<n; j++)
C[i][k] = C[i][k]+A[i][j]*B[j][k];
}
}
/*Chuong trinh chinh*/
void main() {
int m,n,p;
float A[max][max],B[max][max],C[max][max],D[max][max];
clrscr();
cout<<"Nhap m = ";
cin>>m;
cout<<"Nhap n = ";
cin>>n;
cout<<"Nhap p = ";
cin>>p;
cout<<"Nhap ma tran A cap "<<m<<"x"<<n<<endl;
NhapMaTran(A,m,n,'A');
cout<<"Nhap ma tran B cap "<<m<<"x"<<n<<endl;
NhapMaTran(B,m,n,'B');
cout<<"Nhap ma tran C cap "<<n<<"x"<<p<<endl;
NhapMaTran(C,n,p,'C');
clrscr();
cout<<"Ma tran A";
XuatMaTran(A,m,n);
getch();
cout<<"\n\nMa tran B";
XuatMaTran(B,m,n);
getch();
cout<<"\n\nMa tran C";
XuatMaTran(C,n,p);
getch();
cout<<"\n\nMa tran D = A+B";
CongMaTran(A,B,D,m,n);
XuatMaTran(D,m,n);
getch();
cout<<"\n\nMa tran D = A.C";
NhanMaTran(A,C,D,m,n,p);
XuatMaTran(D,n,p);
getch();
}
Trang 38
Bài tập 3. Hệ phương trình tuyến tính dạng tam giác trên
bn
xn a
nn
x 1 b
n
i a ii i a ij x j , i n 1, n 2,...,1
j i 1
Cài đặt:
#include "conio.h"
#include "iostream.h"
#define max 100
//Nhap ma tran tam giac tren
void Nhap(float A[max][max],int n) {
for(int i = 0; i<n; i++)
for(int j = i; j<n; j++) {
cout<<"a["<<i<<"]["<<j<<"] = ";
cin>>A[i][j];
}
}
/*Nhap ma tran he so tu do*/
void Nhap(float B[max],int n) {
for(int i = 0; i<n; i++) {
cout<<"b["<<i<<"] = ";
cin>>B[i];
}
}
/*Xuat ma tran he so tu do*/
void Xuat(float B[max],int n) {
cout<<"(";
for(int i = 0; i<n-1; i++)
cout<<B[i]<<",";
Trang 39
cout<<B[n-1]<<")";
}
/*Xuat ma tran*/
void Xuat(float A[max][max], int n) {
cout<<"\n";
for(int i=0 ; i<n; i++){
cout<<endl;
for(int j=0 ; j<n; j++)
if(i>j)
cout<<"0\t";
else
cout<<A[i][j]<<"\t";
}
}
/*Xuat nghiem*/
void XuatNghiem(float X[], int n, char * s) {
cout<<"\nNghiem cua he A.X = B\n";
for(int i=0; i<n; i++)
cout<<s<<i+1<<" = "<<X[i]<<endl;
}
/*He tam giac tren*/
char HeTamGiacTren (float A[max][max], float X[max], float B[max], int n ) {
for(int i = n-1; i>=0; i--) {
if (A[i][i]!=0) {
if (i==n-1)
X[i] = B[i]/A[i][i];
else {
X[i] = B[i];
for(int j=i+1; j<n; j++)
X[i]=X[i]-A[i][j]*X[j];
X[i] = X[i]/A[i][i];
}
}
else
return 0;
}
return 1;
}
/*Chuong trinh chinh*/
void main() {
int n;
float A[max][max],B[max],X[max];
clrscr();
Trang 40
cout<<"So phuong trinh n = ";
cin>>n;
cout<<"Nhap vao ma tran tam giac tren A\n";
Nhap(A,n);
cout<<"\nNhap vao ma tran he so B\n";
Nhap(B,n);
clrscr();
cout<<"Ma tran A";
Xuat(A,n);
cout<<"\nMa tran B\n";
Xuat(B,n);
if(HeTamGiacTren(A,X,B,n))
XuatNghiem(X,n,"x");
else
cout<<"\nHe phuong trinh tuyen tinh vo nghiem";
getch();
}
Bài tập 4. Hệ phương trình tuyến tính dạng tam giác dưới
b1
x1 a
11
x 1 b a x , 2 i n
i 1
i a ii i ij j
j 1
Cài đặt:
#include "conio.h"
#include "iostream.h"
#define max 100
//Nhap ma tran tam giac duoi
void Nhap(float A[max][max],int n) {
for(int i = 0; i<n; i++)
Trang 41
for(int j = 0; j<=i; j++) {
cout<<"a["<<i<<"]["<<j<<"] = ";
cin>>A[i][j];
}
}
/*Nhap ma tran he so tu do*/
void Nhap(float B[max],int n) {
for(int i = 0; i<n; i++) {
cout<<"b["<<i<<"] = ";
cin>>B[i];
}
}
/*Xuat ma tran he so tu do*/
void Xuat(float B[max],int n) {
cout<<"(";
for(int i = 0; i<n-1; i++)
cout<<B[i]<<",";
cout<<B[n-1]<<")";
}
/*Xuat ma tran*/
void Xuat(float A[max][max], int n) {
cout<<"\n";
for(int i=0 ; i<n; i++){
cout<<endl;
for(int j=0 ; j<n; j++)
if(i<j)
cout<<"0\t";
else
cout<<A[i][j]<<"\t";
}
}
/*Xuat nghiem*/
void XuatNghiem(float X[], int n, char * s){
cout<<"\nNghiem cua he A.X = B\n";
for(int i=0; i<n; i++)
cout<<s<<i+1<<" = "<<X[i]<<endl;
}
/*He tam giac duoi*/
char HeTamGiacDuoi (float A[max][max], float X[max], float B[max], int n ) {
for(int i = 0; i<n; i++) {
if (A[i][i]!=0) {
if (i==0)
X[i] = B[i]/A[i][i];
Trang 42
else {
X[i] = B[i];
for(int j=0; j<i; j++)
X[i]=X[i]-A[i][j]*X[j];
X[i] = X[i]/A[i][i];
}
}
else
return 0;
}
return 1;
}
/*Chuong trinh chinh*/
void main() {
int n;
float A[max][max],B[max],X[max];
clrscr();
cout<<"So phuong trinh n = ";
cin>>n;
cout<<"Nhap vao ma tran tam giac duoi A\n";
Nhap(A,n);
cout<<"\nNhap vao ma tran he so B\n";
Nhap(B,n);
clrscr();
cout<<"Ma tran A";
Xuat(A,n);
cout<<"\nMa tran B\n";
Xuat(B,n);
if(HeTamGiacDuoi(A,X,B,n))
XuatNghiem(X,n,"x");
else
cout<<"\nHe phuong trinh tuyen tinh vo nghiem";
getch();
}
Trang 43
Bài tập 5. Thuật toán phân rã ma trận A = LU
Quá trình chuyển hoá ma trận A ban đầu thành tích hai ma trận tam giác L.U dựa vào
phép khử Gauss được thực hiện bằng các phép nhân ma trận. Thuật toán này được gọi
là thuật toán Crout. Quá trình Crout bao gồm nhiều bước hồi quy. Nếu ma trận A có
cấp n n ta cần n 1 bước. Thuật toán được thể hiện cụ thể như sau:
a wT
a wT 1 0 11
11 Crout 0 H vw a11 L n U n
T
v H 1 v a11 I n 1
A n 1
1 0 ..... 0 u11 u12 ..... u1n
l 1 ..... 0 0 a 22 ..... a2 n 1 0 u11 u1T
21 l I 0
... ... ..... ... ... ..... An1
1 n1
l 0 ..... 1 0 an 2 ..... a nn
n1
1 0 u11 u1T 1 0 u11 u1T
Crout
2 l1 I n 1 0 L n1U n1 l1 L n 1 0 U n1
1 0 0 ..... 0 u11 u12 .... u1n
l 21 1 0 ..... 0 0 u 22 .... u 2 n
Crout ....
l 31 l 32 0 0
... ... I n 2 ... ... A n2
l n1 l n2 0 0
1 0 ..... 0 u11 u12 ... u1n
l21 1 ..... 0 0 u 22 .... u 2 n
Crout
... ... ..... ... ... .... L.U
n 1
l ln 2 ..... 1 0 0 .... u nn
n1
Thông qua n 1 bước hồi quy ta được A L.U với L là ma trận tam giác dưới và U
là ma trận tam giác trên.
Cài đặt:
#include "conio.h"
#include "iostream.h"
#define max 100
void Nhap(float A[max][max],int n) {
for(int i = 0; i<n; i++)
for(int j = 0; j<n; j++) {
cout<<"a["<<i<<"]["<<j<<"] = ";
cin>>A[i][j];
Trang 44
}
}
void XuatMaTran(float A[max][max], int n) {
cout<<"\n";
for(int i=0 ; i<n; i++){
cout<<endl;
for(int j=0 ; j<n; j++)
cout<<A[i][j]<<"\t";
}
}
/*Phan ra A = LU*/
void PhanRaLU(float A[max][max], float L[max][max], float U[max][max], int n) {
for(int k =0; k<n; k++) {
U[k][k] = A[k][k];
L[k][k] = 1;
for(int i=k+1; i<n; i++) {
L[i][k] = A[i][k]/U[k][k];
U[k][i] = A[k][i];
U[i][k] = 0;
L[k][i] = 0;
}
for(i = k+1; i<n; i++)
for(int j = k+1; j<n; j++)
A[i][j] = A[i][j]-L[i][k]*U[k][j];
}
}
void main() {
int n;
float A[max][max],L[max][max],U[max][max];
clrscr();
cout<<"Nhap n = ";
cin>>n;
cout<<"Nhap ma tran A\n";
Nhap(A,n);
cout<<"Ma tran A vua nhap";
XuatMaTran(A,n);
PhanRaLU(A,L,U,n);
cout<<"\nMa tran L";
XuatMaTran(L,n);
cout<<"\nMa tran U";
XuatMaTran(U,n);
getch();
}
Trang 45
Bài tập 6. Giải hệ phương trình tuyến tính dựa vào phân rã LU
Ý tưởng thuật toán: cho hệ phương trình tuyến tính tổng quát A. X B . Ta tiến hành
phân rã A L.U . Trong đó, L là ma trận tam giác dưới và U là ma trận tam giác trên.
Khi đó,
L.Y B
A. X B L.U . X B
U . X Y
Cài đặt:
#include "conio.h"
#include "iostream.h"
#define max 100
/*Nhap ma tran he so*/
void Nhap(float A[max][max],int n) {
for(int i = 0; i<n; i++)
for(int j = 0; j<n; j++) {
cout<<"a["<<i<<"]["<<j<<"] = ";
cin>>A[i][j];
}
}
/*Nhap ma tran he so tu do*/
void Nhap(float B[max],int n) {
for(int i = 0; i<n; i++) {
cout<<"b["<<i<<"] = ";
cin>>B[i];
}
}
/*Xuat ma tran he so tu do*/
void Xuat(float B[max],int n) {
cout<<"(";
for(int i = 0; i<n-1; i++)
cout<<B[i]<<",";
cout<<B[n-1]<<")";
}
/*Xuat ma tran*/
void Xuat(float A[max][max], int n) {
cout<<"\n";
for(int i=0 ; i<n; i++){
cout<<endl;
for(int j=0 ; j<n; j++)
cout<<A[i][j]<<"\t";
}
}
Trang 46
/*Xuat nghiem*/
void XuatNghiem(float X[], int n, char * s) {
cout<<"\nNghiem cua he PTTT";
for(int i=0; i<n; i++)
cout<<s<<i+1<<"="<<X[i];
}
char HeTamGiacDuoi (float A[max][max], float X[max], float B[max], int n ) {
for(int i = 0; i<n; i++) {
if (A[i][i]!=0) {
if (i==0)
X[i] = B[i]/A[i][i];
else {
X[i] = B[i];
for(int j=0; j<i; j++)
X[i]=X[i]-A[i][j]*X[j];
X[i] = X[i]/A[i][i];
}
} else
return 0;
}
return 1;
}
char HeTamGiacTren (float A[max][max], float X[max], float B[max], int n ) {
for(int i = n-1; i>=0; i--) {
if (A[i][i]!=0) {
if (i==n-1)
X[i] = B[i]/A[i][i];
else {
X[i] = B[i];
for(int j=i+1; j<n; j++)
X[i]=X[i]-A[i][j]*X[j];
X[i] = X[i]/A[i][i];
}
} else
return 0;
}
return 1;
}
void PhanRaLU(float A[max][max], float L[max][max], float U[max][max], int n) {
for(int k =0; k<n; k++) {
U[k][k] = A[k][k];
L[k][k] = 1;
for(int i=k+1; i<n; i++) {
Trang 47
L[i][k] = A[i][k]/U[k][k];
U[k][i] = A[k][i];
U[i][k] = 0;
L[k][i] = 0;
}
for(i = k+1; i<n; i++)
for(int j = k+1; j<n; j++)
A[i][j] = A[i][j]-L[i][k]*U[k][j];
}
}
/*Giai he phuong trinh tong quat LUX=B*/
void GiaiHePTTT(float A[max][max], float X[max], float B[max], int n) {
float L[max][max],U[max][max], Y[max];
cout<<"Phan ra A = L.U\n";
PhanRaLU(A,L,U,n);
cout<<"Ma tran L";
Xuat(L,n);
cout<<"\nMa tran U";
Xuat(U,n);
cout<<"\nGiai LY = B. Nghiem Y";
if(HeTamGiacDuoi(L,Y,B,n)) {
XuatNghiem(Y,n,"\ny");
cout<<"\nGiai UX = Y. Nghiem X";
if(HeTamGiacTren(U,X,Y,n))
XuatNghiem(X,n,"\nx");
else
cout<<"\nHe pttt k co nghiem duy nhat";
} else
cout<<"\nHe pttt k co nghiem duy nhat";
}
void main() {
int n;
float A[max][max], B[max], X[max];
clrscr();
cout<<"Nhap so he phuong trinh n = ";
cin>>n;
cout<<"Nhap ma tran he so A\n";
Nhap(A,n);
cout<<"Nhap ma tran he so tu do B\n";
Nhap(B,n);
GiaiHePTTT(A,X,B,n);
getch();
}
Trang 48
Bài tập 7. Định thức của ma trận
Ý tưởng thuật toán: ta tiến hành phân rã ma trận A L.U .
Ta có: Det(A)=Det(L)*Det(U) mà Det(L) = 1 nên Det(A) = Det(U).
Cài đặt:
#include "conio.h"
#include "iostream.h"
#define max 100
/*Nhap ma tran*/
void Nhap(float A[max][max],int n) {
for(int i = 0; i<n; i++)
for(int j = 0; j<n; j++) {
cout<<"a["<<i<<"]["<<j<<"] = ";
cin>>A[i][j];
}
}
/*Xuat ma tran*/
void XuatMaTran(float A[max][max], int n) {
cout<<"\n";
for(int i=0 ; i<n; i++){
cout<<endl;
for(int j=0 ; j<n; j++)
cout<<A[i][j]<<"\t";
}
}
/*Phan ra A = LU*/
void PhanRaLU(float A[max][max], float L[max][max], float U[max][max], int n) {
for(int k = 0; k<n; k++) {
U[k][k] = A[k][k];
L[k][k] = 1;
for(int i=k+1; i<n; i++) {
L[i][k] = A[i][k]/U[k][k];
U[k][i] = A[k][i];
U[i][k] = 0;
L[k][i] = 0;
}
for(i = k+1; i<n; i++)
for(int j = k+1; j<n; j++)
A[i][j] = A[i][j]-L[i][k]*U[k][j];
}
}
//dinh thuc ma tran tam giac
double DinhThucMaTranTamGiac(float A[max][max], int n) {
Trang 49
double temp = 1;
for(int i = 0; i<n; i++)
temp*=A[i][i];
return temp;
}
/*chuong trinh chinh*/
void main() {
int n;
float A[max][max],L[max][max],U[max][max];
clrscr();
cout<<"Nhap n = ";
cin>>n;
cout<<"Nhap ma tran A\n";
Nhap(A,n);
cout<<"Ma tran A vua nhap";
XuatMaTran(A,n);
PhanRaLU(A,L,U,n);
cout<<"\nMa tran L";
XuatMaTran(L,n);
cout<<"\nMa tran U";
XuatMaTran(U,n);
cout<<"\nDet(A) = Det(L)*Det(U) = "<<DinhThucMaTranTamGiac(U,n);
getch();
}
Trang 50
CHƯƠNG 4. MỘT SỐ THUẬT GIẢI TRÊN ĐỒ THỊ
Bai1.inp OUTPUT
6
011000
101000 DO THI KHONG
110000 LIEN THONG
000011
000101
000110
Trang 51
Cài đặt:
#include <stdio.h>
#include <conio.h>
#include <iostream.h>
#define TenFile "Bai1.inp"
//doc du lieu tu tap tin
void Doc_File(int **A,int &n) {
FILE*f = fopen(TenFile,"rb");
fscanf(f,"%d",&n);
*A = new int [n];
cout<<"Ma Tran Lien Ket Cua Do Thi";
for(int i =0;i<n;i++) {
A[i] = new int [n];
cout<<endl;
for(int j =0;j<n;j++) {
fscanf(f,"%d",&A[i][j]);
cout<<" "<<A[i][j];
}
}
fclose(f);
}
//kiem tra tinh lien thong neu lien thong tra ve gia tri 1 nguoc lai tra ve gia tri 0
char Lien_Thong(int **A,int n) {
char*DanhDau = new char [n];
char ThanhCong;
int Dem=0;
for(int i = 0; i<n; i++) //Khoi tao moi dinh chua danh dau
DanhDau[i] = 0;
DanhDau[0] = 1; //danh dau dinh dau
Dem++; //dem so dinh duoc danh dau
do {
ThanhCong =1; //khong con kha nang loang
for(i = 0; i<n; i++)
if(DanhDau[i]==1)
{
for(int j = 0; j<n; j++)
if (DanhDau[j] == 0 && A[i][j] > 0)
{
DanhDau[j] = 1;
ThanhCong = 0; //con kha nang loang
Dem++;
if(Dem == n)
return 1;
Trang 52
}
}
}while (ThanhCong == 0); //lap lai cho den khi khong con kha nang loan
return 0;
}
//chuong trinh chinh
void main()
{
clrscr();
int **A,n;
Doc_File(A,n);
if (Lien_Thong(A,n)==1)
cout<<"\nDO THI LIEN THONG";
else cout<<"\nDO THI KHONG LIEN THONG";
delete *A;
getch();
}
Trang 53
Bai2.inp OUTPUT
6
011000
101000 THANH PHAN
110000 LIEN THONG: 2
000011
000101
000110
Bai2.inp OUTPUT
8
01000100
10100000
01010000 THANH PHAN
00101000 LIEN THONG: 1
00010100
10001010
00000101
00000010
Cài đặt:
#include <stdio.h>
#include <conio.h>
#include <iostream.h>
#define TenFile "Bai2.inp"
//doc du lieu tu tap tin
void Doc_File(int **A,int &n) {
FILE*f = fopen(TenFile,"rb");
fscanf(f,"%d",&n);
*A = new int [n];
cout<<"Ma Tran Lien Ket Cua Do Thi";
for(int i =0;i<n;i++) {
A[i] = new int [n];
cout<<endl;
for(int j =0;j<n;j++) {
fscanf(f,"%d",&A[i][j]);
cout<<" "<<A[i][j];
}
}
fclose(f);
}
//ham tra ve so thanh phan lien thong cua do thi
int TPLien_Thong(int **A, int n) {
char*DanhDau = new char [n];
char ThanhCong;
Trang 54
int Dem=0, i,j, MLT=0;
for( i = 0; i<n; i++) //khoi tao cac dinh chua danh dau
DanhDau[i] = 0;
do {
j = 0;
while(DanhDau[j]==1) //tim 1 dinh chua duoc danh dau
j++;
DanhDau[j] = 1; //danh dau dinh tim duoc
Dem++; //tang so dinh danh dau len 1
MLT++; //tang so thanh phan lien thong len 1
do {
ThanhCong =0;
for(i = 0; i<n; i++)
if(DanhDau[i]==1)
for(j = 0; j<n; j++)
if (DanhDau[j] == 0 && A[i][j] > 0) {
DanhDau[j] = 1;
ThanhCong =1;
Dem++;
if(Dem == n) return MLT;
}
}while (ThanhCong == 1);
} while(Dem<n); //lap lai khi con dinh chua duoc danh dau
return MLT;
}
//chuong trinh chinh
void main() {
clrscr();
int **A,n;
Doc_File(A,n);
cout<<"\nTHANH PHAN LIEN THONG: "<<TPLien_Thong(A,n);
delete *A;
getch();
}
Trang 55
Bài tập 3. Tìm mọi đường đi từ giữa hai đỉnh
Mô tả bài toán: cho đồ thị vô hướng G=(V,E) hãy xác định mọi đường đi từ đỉnh D tới
đỉnh C của đồ thị G.
Ý tưởng thuật toán: sử dụng kỹ thuật tìm kiếm theo chiều sâu.
Bai3.inp OUTPUT
6
14
011000 KHONG CO
101000 DUONG DI
110000
000011
000101
000110
Cài đặt:
#include <stdio.h>
#include <conio.h>
#include <iostream.h>
#define FileIn "Bai3.inp"
int Dem = 0; //dem so duong di
int *L; //luu duong di
char *DanhDau; //danh dau dinh da di
int **A,n,D,C;
//doc du lieu tu tap tin
void Doc_File() {
Trang 56
FILE*f = fopen(FileIn,"rb");
fscanf(f,"%d%d%d",&n,&D,&C);
cout<<"Ma Tran Lien Ket Tuong Ung.\n"<<D<<" "<<C<<endl;
*A = new int [n];
for(int i =0;i<n;i++) {
A[i] = new int [n];
for(int j =0;j<n;j++) {
fscanf(f,"%d",&A[i][j]);
cout<<A[i][j]<<" ";
}
cout<<endl;
}
fclose(f);
D--;
C--;
}
//khoi tao cac bien ban dau cho bai toan
void KhoiTao() {
DanhDau = new char [n];
L = new int [n];
for (int i = 0; i<n; i++) {
DanhDau[i] = 0;
L[i] = 0;
}
DanhDau[D] = 1; //danh dau dinh dau tien
L[0] = D; //luu dinh dau tien la dinh xuat phat
}
void InDuongDi(int SoCanh) {
Dem++;
cout<<endl<<D+1;
for (int i = 1; i<SoCanh; i++)
cout<<" -> "<<L[i]+1;
}
//thu tuc tim kiem duong di
void Try(int SoCanh) {
if(L[SoCanh-1] == C) //xuat duong di
InDuongDi(SoCanh);
else {
for(int i = 0; i<n; i++)
if( A[L[SoCanh-1]][i]>0 && DanhDau[i] == 0 ){
L[SoCanh] = i; //luu dinh da di qua
DanhDau[i] = 1; //danh dau dinh da di qua
Try(SoCanh+1); //tim kiem dinh tiep theo
Trang 57
L[SoCanh] = 0;
DanhDau[i] = 0; //phuc hoi dinh da di qua
}
}
}
//chuong trinh chinh
void main() {
Doc_File();
KhoiTao();
cout<<"Duong di tu "<<D+1<<" den "<<C+1;
Try(1);
if(Dem==0)
cout<<" khong co duong di";
delete*A,DanhDau,L;
getch();
}
Trang 58
Bai4.inp OUTPUT
5
1
01000
10111 12345
01010
01101
01010
Cài đặt:
#include <stdio.h>
#include <conio.h>
#include <iostream.h>
#define FileIn "Bai4.inp"
int Dem = 0; //dem so duong di
int *L; //luu duong di
char *DanhDau; //danh dau dinh da di
int **A,n,D;
//doc du lieu tu tap tin theo yeu cau cua bai toan
void Doc_File() {
FILE*f = fopen(FileIn,"rb");
fscanf(f,"%d%d",&n,&D);
cout<<"Ma Tran Lien Ket Tuong Ung.\n"<<D<<endl;
*A = new int [n];
for(int i =0;i<n;i++) {
A[i] = new int [n];
for(int j =0;j<n;j++) {
fscanf(f,"%d",&A[i][j]);
cout<<A[i][j]<<" ";
}
cout<<endl;
}
fclose(f);
D--;
}
//khoi tao du lieu ban dau cho bai toan
void KhoiTao() {
DanhDau = new char [n];
L = new int [n];
for (int i = 0; i<n; i++) {
DanhDau[i] = 0; //tat ca cac dinh dieu danh dau
L[i] = 0;
}
DanhDau[D] = 1; //danh dau dinh xuat phat
Trang 59
L[0] = D;
}
//xuat duong di ra man hinh
void InDuongDi(int Dinh) {
Dem++;
cout<<endl<<D+1;
for (int i = 1; i<Dinh; i++)
cout<<" -> "<<L[i]+1;
}
//tim kiem duong di
void Try(int Dinh) {
if(Dinh == n)
InDuongDi(Dinh);
else {
for(int i = 0; i<n; i++)
if( A[L[Dinh-1]][i]>0 && DanhDau[i] == 0){
L[Dinh] = i;
DanhDau[i] = 1; //danh dau dinh da di qua
Try(Dinh+1); //tim kiem dinh tiep theo
L[Dinh] = 0;
DanhDau[i] = 0; //phuc hoi dinh da danh dau
}
}
}
void main() {
clrscr();
Doc_File();
KhoiTao();
cout<<"Duong di";
Try(1);
if(Dem==0)
cout<<" khong co.";
delete*A,DanhDau,L;
getch();
}
Trang 60
Bài tập 5. Đường đi Euler
Mô tả bài toán: cho đồ thị vô hướng G=(V,E) hãy xác định mọi đường đi qua tất cả các
cạnh mỗi cạnh chỉ qua duy nhất 1 lần.
Ý tưởng thuật toán: sử dụng kỹ thuật tìm kiếm theo chiều sâu bằng cách xóa cạnh đã
đi qua trong quá trình tìm kiếm đường đi.
Mô tả dữ liệu đầu vào và đầu ra của bài toán:
Dữ liệu vào: cho trong tập tin Bai5.inp
- Dòng đầu ghi số n là số đỉnh của một đồ thị (0<n<100)
- Dòng i+1 (1 i n ) chứa n số A[i,1],A[i,2]…A[i,n] mỗi số cách nhau bởi
một khoảng trắng.
Dữ liệu ra: in ra màn hình đường đi qua tất cả các cạnh (nếu có).
Ví dụ:
Bai5.inp OUTPUT
5
01000
10111
01010 4->2->3->4->5->2->1
01101
01010
Cài đặt:
#include <stdio.h>
#include <conio.h>
#include <iostream.h>
#define Filename "Bai5.inp"
int Dem = 0, SoCanh=0; //dem so duong di va luu so canh cua do thi
int *L; //luu dinh da di qua
int **A,n;
int XuatPhat=0; //dinh xuat phat la dinh bac le neu do thi co dinh bac le
void Doc_File() {
int BacDinh;
FILE*f = fopen(Filename,"rb");
fscanf(f,"%d",&n);
cout<<"Ma Tran Lien Ket Tuong Ung.\n"<<n<<endl;
*A = new int [n];
for(int i =0;i<n;i++) {
A[i] = new int [n];
BacDinh = 0;
for(int j =0;j<n;j++) {
fscanf(f,"%d",&A[i][j]);
cout<<A[i][j]<<" ";
Trang 61
if(A[i][j] == 1)
BacDinh++;
}
if(BacDinh%2==1)
XuatPhat = i; //xuat phat tu dinh bac le
SoCanh+=BacDinh;
cout<<endl;
}
fclose(f);
SoCanh = SoCanh/2; //so canh = so dinh chia 2
L = new int [SoCanh+1];
L[0] = XuatPhat;
}
void InDuongDi() {
Dem++;
cout<<endl<<XuatPhat+1;
for (int i = 1; i<=SoCanh; i++)
cout<<" -> "<<L[i]+1;
}
//thu tuc tim kiem de quy
void Try(int Canh) {
if(Canh > SoCanh) //tim du so canh thi xuat duong di
InDuongDi();
else {
for(int i = 0; i<n; i++)
if( A[L[Canh-1]][i]>0){
L[Canh] = i;
A[L[Canh-1]][i]=A[i][L[Canh-1]]=0; //xoa canh
Try(Canh+1); //tim canh tiep theo
A[L[Canh-1]][i]=A[i][L[Canh-1]]=1; //phuc hoi canh
L[Canh] = 0;
}
}
}
void main() {
Doc_File();
cout<<"\nDUONG DI";
Try(1);
if(Dem==0)
cout<<" KHONG CO";
delete*A,L;
getch();
}
Trang 62
Bài tập 6. Thuật toán Dijkstra tìm đường đi ngắn nhất
Mô tả bài toán: cho đồ thị vô hướng G=(V,E) hãy xác định đường đi ngắn nhất từ đỉnh
D tới đỉnh C của đồ thị G.
Ý tưởng thuật toán: sử dụng thuật toán Dijkstra.
Mô tả dữ liệu đầu vào và đầu ra của bài toán:
Dữ liệu vào: đồ thị đã liên thông và cho trong tập tin Bai6.inp.
- Dòng đầu ghi số n là số đỉnh của một đồ thị (0<n<100)
- Dòng thứ hai lưu đỉnh D và đỉnh C.
- Dòng i+2 ( 1 i n ) chứa n số A[i,1],A[i,2]…A[i,n] mỗi số cách nhau bởi
một khoảng trắng.
Dữ liệu ra: xuất ra màn hình đường đi ngắn nhất từ đỉnh D đến C và giá trị đường đi
ngắn nhẩt tìm được.
Ví dụ:
Bai6.inp Output
6
16
012000 DUONG DI NGAN
102230 NHAT LA: 5
220540 1246
025032
034304
000240
Cài đặt:
#include <stdio.h>
#include <conio.h>
#include <iostream.h>
#include <values.h>
#define max 100
#define FileIn "Bai6.inp"
void Doc_File(int A[max][max], int &n, int &D, int &C) {
FILE*f = fopen(FileIn,"rb");
fscanf(f,"%d%d%d",&n,&D,&C);
cout<<"Ma Tran Lien Ket Tuong Ung.\n";
cout<<D<<" "<<C<<endl;
for(int i =0;i<n;i++) {
for(int j =0;j<n;j++) {
fscanf(f,"%d",&A[i][j]);
cout<<A[i][j]<<" ";
}
cout<<endl;
Trang 63
}
fclose(f);
D--; C--;
}
void Dijkstra(int A[max][max], int n, int D, int C) {
char DanhDau[max];
int Nhan[max], Truoc[max], XP, min;
for(int i=0; i<n; i++){
Nhan[i] = MAXINT;
DanhDau[i] = 0;
Truoc[i] = D;
}
Nhan[D] = 0;
DanhDau[D] = 1;
XP = D;
while(XP != C){
for(int j=0; j<n; j++)
if(A[XP][j]>0 && Nhan[j]>A[XP][j]+Nhan[XP] && DanhDau[j]==0) {
Nhan[j] = A[XP][j]+Nhan[XP];
Truoc[j] = XP;
}
min = MAXINT;
for(j = 0; j<n; j++)
if(min>Nhan[j]&& DanhDau[j]==0){
min = Nhan[j];
XP = j;
}
DanhDau[XP] = 1;
}
cout<<"Duong Di Ngan Nhat La:"<<Nhan[C]<<endl;
cout<<C+1<<" <- "<<Truoc[C]+1;
i = Truoc[C];
while(i!=D){
i = Truoc[i];
cout<<" <- "<<i+1;
}
}
void main() {
int A[max][max],n,Dau,Cuoi;
Doc_File(A,n,Dau,Cuoi);
Dijkstra(A,n,Dau,Cuoi);
getch();
}
Trang 64
Bài tập 7. Thuật toán Prim tìm cây bao trùm tối tiểu
Mô tả bài toán: cho đồ thị vô hướng có trọng số G=(V,E) hãy tìm đường đi sao cho tất
cả các đỉnh điều có đường đi với nhau và tổng trọng số của đường đi là nhỏ nhất. Tức là
tìm đồ thị con liên thông G ' G sao cho tổng trọng số của G’ là nhỏ nhất.
Ý tưởng thuật toán:
Bước 1: xuất phát từ đỉnh k bất kỳ (thông thường chọn đỉnh đầu tiên) chọn một cạnh có
trọng số nhỏ nhất liền kề với đỉnh k (min{A[k][j]}j=1..n) ta đánh dấu 2 đỉnh đi qua
cạnh đó và số cạnh tìm được là 1. Chuyển sang Bước 2.
Bước 2: tìm cạnh nhỏ nhất của đồ thị với điều kiện cạnh tìm được phải có 1 đỉnh chưa
đánh dấu và 1 đỉnh đã đánh dấu. Nghĩa là, ta tìm min{A[i][j]}j=1..n, i=1..n sao
cho i đánh đấu và j chưa đánh dấu để tránh trường hợp tạo thành chu trình
con. Ta tăng số cạnh tìm được lên 1 và chuyển sang Bước 3.
Bước 3: nếu số cạnh tìm được bằng n-1 kết thúc thuật toán, ngược lại quay về Bước 2.
Mô tả dữ liệu đầu vào và đầu ra của bài toán:
Dữ liệu vào: lưu trong tập tin Bai7.inp
- Dòng đầu ghi số n là số đỉnh của một đồ thị (0<n<100)
- Dòng i+1 ( 1 i n ) lưu ma trận kề của đồ thị với n số A[i,1],A[i,2]…A[i,n]
mỗi số cách nhau bởi một khoảng trắng.
Dữ liệu ra: lưu trong file Bai7.out
- Dòng đầu ghi trọng số nhỏ nhất của cây bao trùm.
- Các dòng còn lại lưu đường đi giữa đỉnh i nối với đỉnh j.
Ví dụ:
Bai7.inp Bai7.out
5 7
03322 1-4
30238 4-3
32014 1-5
23104 3-2
28440
Cài đặt:
#include <stdio.h>
#include <values.h>
#define max 100
#define FileInt "Bai7.inp"
#define FileOut "Bai7.out"
typedef struct Egde {
int x,y;
};
Trang 65
//doc du lieu tu tap tin
void Doc_File(int A[max][max],int &n) {
FILE*f = fopen(FileInt,”rb”);
fscanf(f,”%d”,&n);
for(int i =0;i<n;i++) {
for(int j =0;j<n;j++) {
fscanf(f,”%d”,&A[i][j]);
}
}
fclose(f);
}
//xuat du lieu ra tap tin
void Ghi_File(Egde L[max],int n,int Sum) {
FILE*f = fopen(FileOut,"wb");
fprintf(f,"%d\n",Sum);
for(int i =0; i<n-1; i++)
fprintf(f,"%d - %d\n",L[i].x+1,L[i].y+1);
fclose(f);
}
//thuat toan Prim
void Prim(int A[max][max], int n) {
char D[max];
Egde L[max];
int min = MAXINT, Dem = 0, Sum = 0;
for(int i=0; i<n; i++)
D[i]=0;
for(int j=1; j<n; j++)
if(min>A[0][j] && A[0][j]!=0){
min = A[0][j];
L[0].y = j;
}
L[0].x = 0;
D[0] = 1;
D[L[0].y] = 1;
Sum+=min;
Dem++;
do {
min = MAXINT;
for( i=0; i<n; i++)
if(D[i]==1)
for( j=0; j<n; j++)
if(A[i][j]>0 && min>A[i][j] && D[j]==0){
min = A[i][j];
Trang 66
L[Dem].x = i;
L[Dem].y = j;
}
Sum+=min;
D[L[Dem].y] = 1;
Dem++;
} while(Dem<n-1);
Ghi_File(L,n,Sum);
}
//chuong trinh chinh
void main() {
int A[max][max],n;
Doc_File(A,n);
Prim(A,n);
}
Bài tập 8. Thuật toán Kruskal tìm cây bao trùm tối tiểu
Mô tả bài toán: cho đồ thị vô hướng có trọng số G=(V,E) hãy tìm đường đi sao cho tất
cả các đỉnh điều có đường đi với nhau và tổng trọng số của đường đi là nhỏ nhất. Tức là
tìm đồ thị con liên thông G' G sao cho tổng trọng số của G’ là nhỏ nhất.
Ý tưởng thuật toán:
Bước 0: khởi tạo tập cạnh tìm được là rỗng và chuyển sang Bước 1.
Bước 1: chọn một cạnh có trọng số nhỏ nhất sao cho khi đưa cạnh này vào tập cạnh tìm
được không tạo thành chu trình. Tăng số cạnh tìm được lên 1 và chuyển sang
Bước 2.
Bước 2: nếu số cạnh tìm được bằng n-1 thuật toán kết thúc, ngược lại quay về Bước 1.
Mô tả dữ liệu đầu vào và đầu ra của bài toán:
Dữ liệu vào: lưu trong tập tin Bai8.inp
- Dòng đầu ghi số n là số đỉnh của một đồ thị (0<n<100)
- Dòng i+1 ( 1 i n ) lưu ma trận kề của đồ thị với n số A[i,1],A[i,2]…A[i,n]
mỗi số cách nhau bởi một khoảng trắng.
Dữ liệu ra: lưu trong file Kruskal.out
- Dòng đầu ghi trọng số nhỏ nhất của cây bao trùm.
- Các dòng còn lại lưu đường đi giữa đỉnh i nối với đỉnh j.
Trang 67
Ví dụ:
Bai8.inp Bai8.out
8 20
02340000 6-7
20304000 1-2
33076520 3-7
40700030 1-3
04600408 4-7
00504016 2-5
00230105 7-8
00008650
Cài đặt:
#include <stdio.h>
#include <values.h>
#define FileInt "Bai8.inp"
#define FileOut "Bai8.out"
typedef struct Egde {
int x,y;
};
//doc du lieu tu tap tin
void Doc_File(int **A,int &n) {
FILE*f = fopen(FileInt,"rb");
fscanf(f,"%d",&n);
*A = new int [n];
for(int i =0;i<n;i++) {
A[i] = new int [n];
for(int j =0;j<n;j++) {
fscanf(f,"%d",&A[i][j]);
}
}
fclose(f);
}
//ghi du lieu ra tap tin
void Ghi_File(Egde*L,int n,int Sum) {
FILE*f = fopen(FileOut,"wb");
fprintf(f,"%d\n",Sum);
for(int i =0; i<n-1; i++)
fprintf(f,"%d - %d\n",L[i].x+1,L[i].y+1);
fclose(f);
}
void Kruskal(int **A, int n) {
int *D = new int[n];
Egde *L = new Egde[n-1];
Trang 68
int min = MAXINT, Dem = 0, Sum = 0, T = 0, Temp;
for(int i=0; i<n; i++)
D[i] = 0;
do{
min = MAXINT;
for( i=0; i<n; i++)
for(int j=0; j<n; j++)
if(A[i][j]>0 && min>A[i][j]&& !(D[i]!=0 && D[i]==D[j])) {
min = A[i][j];
L[Dem].x = i;
L[Dem].y = j;
}
if(D[L[Dem].x] ==0 && D[L[Dem].y] == 0){
T++;
D[L[Dem].x] = D[L[Dem].y] = T;
}
if(D[L[Dem].x] == 0 && D[L[Dem].y] != 0){
D[L[Dem].x] = D[L[Dem].y];
}
if(D[L[Dem].x] != 0 && D[L[Dem].y] == 0){
D[L[Dem].y] = D[L[Dem].x];
}
if(D[L[Dem].x] != D[L[Dem].y] && D[L[Dem].y]!=0) {
Temp = D[L[Dem].x];
for( i=0; i<n; i++)
if(Temp==D[i])
D[i]=D[L[Dem].y];
}
Sum+=min;
Dem++;
} while(Dem<n-1);
Ghi_File(L,n,Sum);
}
//chuong trinh chinh
void main() {
int **A,n;
Doc_File(A,n);
Kruskal(A,n);
delete *A;
}
Trang 69
TÀI LIỆU THAM KHẢO
[1] Chu Đức Khánh, Nguyễn Cam, Lý thuyết đồ thị, NXB Đại học Quốc gia
TPHCM.
[2] Dương Thủy Vỹ, Giáo trình Phương pháp tính, NXB KHKT.
[3] Ngọc Anh Thư, Giáo trình thuật toán, NXB Thống kê.
[4] Ngô Đắc Tân, Lý thuyết tổ hợp và đồ thị, NXB ĐH Quốc gia Hà Nội.
[5] Dương Vũ Diệu Trà, Nguyễn Tiến Huy, Trần Đan Thư, Vũ Mạnh Trường, Cẩm
nang thuật toán, NXB KHKT.
[6] Đỗ Xuân Lôi, Cấu trúc dữ liệu & Giải thuật, 1995.
[7] Nguyễn Đức Nghĩa, Tô Văn Thành, Toán rời rạc, 1997.
[8] A.V. Aho, J.E. Hopcroft, J.D. Ullman, Data Structures and Algorithms, Addison
– Wesley, 1983.
[9] Jeffrey H Kingston, Algorithms and Data Structures, Addison-Wesley, 1998.