Toán rời rạc là một lĩnh vực của toán học nghiên cứu các đối tượng rời rạc. Chúng ta sẽ phải sử dụng công cụ của toán rời rạc khi phải đếm các đối tượng,khi nghiên cứu quan hệ giữa các tập rời rạc,khi phân tích các quá trình hữu hạn. Một trong những nguyên nhân chủ yếu làm nâng tầm quan trọng của toán rời rạc là việc cất giữ và xử lý thông tin trên máy tính bản chất là các quá trình rời rạc.Và ba lĩnh vực có nhiều ứng dụng của toán rời rạc lý thuyết tổ hợp,lý thuyết đồ thị và hàm số logic. Vì vậy,việc học toán rời rạc rất là quan trọng.Và môn Thực hành Toán rời rạc có nhiêm vụ là bổ sung và củng cố lại các kiến thức đã học,và biết được những ứng dụng của Toán rời rạc trên thực tế.
Trang 1MỤC LỤC
MỤC LỤC 1
LỜI NÓI ĐẦU 2
Bài toán đếm & Bài toán liệt kê 4
Bài 1 4
Bài 2 4
Bài 3 6
Bài 4 8
Bài toán tối ưu rời rạc 11
Bài 1 11
Bài 2 12
Bài toán trên đồ thị 16
Thuật toán 16
Chương trình 18
Bài toán luồng cực đại trên mạng 22
Thuật toán 22
Chương trình 24
Trang 2LỜI NÓI ĐẦU
Toán rời rạc là một lĩnh vực của toán học nghiên cứu các đối tượng rời rạc Chúng ta sẽ phải sử dụng công cụ của toán rời rạc khi phải đếm các đối tượng,khi nghiên cứu quan hệ giữa các tập rời rạc,khi phân tích các quá trình hữu hạn Một trong những nguyên nhân chủ yếu làm nâng tầm quan trọng của toán rời rạc là việc cất giữ và xử lý thông tin trên máy tính bản chất là các quá trình rời rạc.Và ba lĩnh vực có nhiều ứng dụng của toán rời rạc lý thuyết tổ hợp,lý thuyết đồ thị và hàm số logic.
Vì vậy,việc học toán rời rạc rất là quan trọng.Và môn Thực hành Toán rời rạc
có nhiêm vụ là bổ sung và củng cố lại các kiến thức đã học,và biết được những ứng dụng của Toán rời rạc trên thực tế.
Trang 3Phần I Bài toán liệt kê
Trang 4Bài toán đếm & Bài toán liệt kê
=============
Bài 1:
Đếm số xâu nhị phân độ dài n:
a) Bất kỳ
b) Không có hai bit 0 kề Nhau
c) Có ít nhất hai bit 0 kề nhau
Bài 2:
Viết chương trình liệt kê tất cả các xâu nhị phân độ dài n như yêu cầu của bài toán 1.Liệt kê có số thứ tự để kiểm tra kết quả đã đếm được.Thử nhập với nhiều giá trị khác nhau của n.Lưu ý các trường hợp n=1 và n=2
Thuật toán
Thuật toán chung cho cả hai bài là liệt kê bằng phương pháp đệ quy Sử dụng hàm “chỉnh hợp lặp chập n của k loại phần tử” (với n=độ dài xâu nhị phân, k=0 hoặc 1.)
{ case 1: in(); break;
case 2: not2bit0(); break;
case 3: two_bit0(); break;
Trang 5printf(" nhap do dai n cua xau la:"); scanf("%d",&n);
// -in ra xau bat ky -//
printf("\n Cac xau nhi phan bat ky voi do dai la :%d\n",n);
lietke(1,1);
delay(5000);
// -in ra cac xau ko co 2 bit 0 ke nhau -//
printf("\n Cac xau nhi phan ko co 2 bit 0 ke nhau :\n");
d=0;
lietke(1,2);
delay(5000);
// -in ra cac xau CO 2 bit 0 ke nhau -//
printf("\n Cac xau nhi phan CO 2 bit ko ke nhau :\n");
{ case 1: in(); break;
case 2: not2bit0(); break;
case 3: two_bit0(); break;
Trang 6Viết chương trình nhập 1 xâu chữ gồm n các chữ cái hoa (A…Z) trong đó có
1 số chữ cái lặp.Liệt kê tất cả các cách sắp xếp n chữ cái này.Có đếm tổng
số cách sắp xếp.
Thuật toán
Thuật toán chung là liệt kê bằng phương pháp sinh kế tiếp Sử dụng hàm “hoán vị lặp của n phần tử” (với n=độ dài xâu chữ.) bằng cách thêm dấu bằng (=) vào biểu thức so sánh s[i] và s[j] (in đậm) ở hàm hoán vị n phần tử.
Trang 7void xauchuan(char *s,int n);
void hoanvi(char &a,char &b);
void phantu(char *s,char *a,int n,int &k);
long hoanvilap(char *a,int n,int k);
printf(" Nhap 1 xau ky tu: \n"); gets(s);
printf("> -> Xau ban vua nhap la:"); puts(s);
Trang 9Bài 4:
Xét phương trình nguyên :
x1 + x2 + ….+ xn = k với xi>=0 mọi i=1 k
Viết chương trình nhập n và k,rồi in ra tất cả các nghiệm của phương
trình.Có đếm tổng số nghiệm.
Thuật toán
Thuật toán chung cho cả hai bài là liệt kê bằng phương pháp đệ quy Sử dụng hàm “chỉnh hợp lặp chập n của k loại phần tử” (với n là số phần tử, k là tổng ) Đoạn code
Trang 10void thu(int i);
printf("so phan tu X la: n=");scanf("%d",&n);
printf("Tong cua pt la: k=");scanf("%d",&k);
Trang 12Phần II:
Bài toán tối ưu rời rạc
Bài toán tối ưu rời rạc
===========
Bài 1:
Viết chương trình nhập n là số chi tiết cần gia công và nhập vào thời gian gia công 2 máy của từng chi tiết.Tính và in ra thời gian hoàn thành gia công nhanh nhất.
Thuật toán
- Nhập vào số chi tiết n
- Nhập vào thời gian gia công của từng chi tiết trên 2 máy A,B Đưa vào 2 biến mảng 1 chiều: thoi_gian1[i] và thoi_gian2[i].
- So sánh hai thời gian đó và cộng dồn cái nhỏ hơn
Trang 14Viết chương trình nhập n là số thành phố và nhập ma trận khoảng cách
void thu(int i);
void xuatmt(int c[20][20],int n);
xuatmt(c,n);
}
Trang 15int min_khoangcach()
//Tim gia tri nho nhat cua ma tran khong nam tren duong cheo chinh
{ int i,j, min=2000;
Trang 16thu(i+1);
} b[j]=1;
Trang 17Phần III:
Bài toán trên đồ thị
Trang 18Bài toán trên đồ thị
=============
Viết chương trình phát sinh ngẫu nhiên ma trận trọng số Anxn=(aij)nxn của đồ thị vô hướng liên thông G gồm n đỉnh ( aij=aji với mọi I,j=1…n).
a) Kiểm tra đồ thị G có phải là đồ thị Euler hay không
b) Nhập hai đỉnh x,y và dùng thuật toán Dijksrtra để tìm đường đi ngắn nhất từ x đến y.
c) Dùng thuật toán Prim để tìm cây khung phủ nhỏ nhất của đồ thị G.
Kiểm tra Euler
Nếu có quá 2 đỉnh có bậc là bậc lẽ thì ko phải đồ thị Euler
if(kt<=2) printf("do thi la do thi EULER\n\n");
else printf("do thi ko phai la do thi EULER\n\n");
Thuật toán prim
Để tìm cây phủ nhỏ nhất của đồ thị G làm các bước sau
1) Khởi đàu cho T gồm một đỉnh v bất kì và không cạnh
2) Lặp n-1 lần
- Tìm trọng số đỉnh rìa 1 đỉnh v có cạnh nối T là e với e là nhỏ nhất
- Đưa e và v vào T
3) In cây phủ nhỏ nhất và trọng số của nó
Trang 19min=MAX; // nạp cho min = MAX
dinh=1; //khởi tạo tại đỉnh 1
dinh=phu; // nạp cho đỉnh tiêp theo của vòng lặp kế tiếp
if(min!=MAX) dem+=min;// nếu min khác vô cùng thì nộp min vào tổng trọng số
min=MAX;//xác lập lại min
}
}
Thuật toán Dijkstra
1) Bắt đàu từ đỉnh A , nạp D(A)=0,và D(i)=vô cùng với mọi i#A Tập T chứa tất cả các đỉnh
2) Trong khi đỉnh Z còn thuộc tập T thì thực hiện các bước sau
- Lấy ra khỏi T đỉnh v(i) có D(i) nhỏ nhất
- Vọi mọi v(j) kề v(i) và v(j) thuộc T đánh nhãn lại D(j) =min{ D(j), [ D(j)+W(ij) ] }
- Khi dỉnh Z không còn thuộc T thì kết thúc thuật toán 3) In ra đường đi và độ dài đường đi nhỏ nhất
4) Đoạn code
void dijkstra()
{ int v,u,minp;
printf("\nTim duong di tu s=");scanf("%d",&s);
printf(" den ");scanf("%d",&t);
Trang 20for(v=1;v<=n;v++)
{ d[v]=cp[s][v];//d nap khoảng cách đỉnh s đến các đỉnh còn lại
truoc[v]=s;//mảng trước là mảng in đường đi
final[v]=0;//xác lập đỉnh chưa dùng
}
truoc[s]=0;
d[s]=0;;//đánh nhãn D(s) =0;
final[s]=0;//đinh s được nạp cuối cùng(chưa được nap)
while(!final[t])//khi đỉnh cuối chưa đùng
/* chuong trinh tim khung cay phu(prim)*/
/* duong di ngan nhat(Dijkstra) */
Trang 21printf("Nhap so dinh cua ma tran n=");
if(kt<=2) printf("do thi la do thi EULER\n\n");
else printf("do thi ko phai la do thi EULER\n\n");
}
// -ham Prim -//
Trang 22min=b[k];
phu=k;
}a[dinh][phu]=MAX;
printf("\nTim duong di tu s=");scanf("%d",&s);
printf(" den ");scanf("%d",&t);
Trang 24Bài toán luồng cực đại trên mạng
Bài toán luồng cực đại trên mạng
Hàm nhập ma trận liên thông có hướng:
1) Tạo ma trận an x x với n là nhập từ bàn phím,n là số đỉnh của đồ thị
2) Vì đồ thị liên thông có hướng và giả sử giữa các đỉnh có sự liên thông.
a) ví dụ từ đỉnh x có khả năng thông qua đỉnh y là c=(aij) thì điều ngược lại
Trang 25d) Vì từ 1 đỉnh không thể có khả năng thông qua là bằng 0, a[i][i]=0 với i=1 n.
3) Nên ta có thuật toán đoạn code :
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i!=j && i!=n && j!=1 && a[j][i]==0 )
do { printf("\ntu dinh %d den %d co kha nang thong qua la:",i,j); scanf("%d",&a[i][j]);
} while( a[j][i]!=0 );
Thuật toán Ford-Fulkerson :
Tìm luồng F(f ij) trên mạng G
Bước 1: Khởi đầu F là luồng 0 : fij=0
Bước 2: Lặp cho đến khi không còn đuờng tăng luồng
- Tìm đường tăng luông P từ đỉnh 1 đến đỉnh n.
- Tăng luồng dọc theo P
- Đánh nhãn lại khả năng thông qua của 1 luồng
- Lấy giá trị khả năng thông qua còn lại nhỏ nhất và cộng vào luồng cực đại.
Bước 3: in ra giá trị luồng cực đại.
Hàm tính luồng cực đại
for(i=1;i<=n;i++)
{
ok=0; // để kiểm tra
for(h=1;h<=n;h++) if(a[1][h]) ok=1; // nếu các phần tử dòng 1 mà đều bằng 0 hêt thì kết thúc thuật toán
if( b[h]<=min ) min=b[h];
for(k=0;k<=50;k++) b[k]=0; // nạp lại các phần tử của mãng b bằng 0 để phục vụ vòng lặp kế tiếp
k=1;// nạp lại giá trị tăng cho mãng b
if(c[phu]==n) // kiểm tra đỉnh kết thúc của luồng P có phải là đích hay không
{ gt+=min; // cập nhập giá trị luồng cực đại
printf("\n Duong di la : 1"); // in đường đi
for(h=1;h<=phu;h++)
printf("%2d",c[h]);
printf(" > -> min=%d\n",min); // in giá trị của mỗi luồng
}
Trang 26i=tam; // trả lại giá trị trị khi bắt đầu vòng lặp của i
if(min)// giá trị luồng khác không
for(j=1;j<=n;j++)//đánh nhãn lại các khả năng thông qua của luồng
if(min) i=0; // nếu giá trị tăng luồng khác không thì bắt đầu lại từ đinh1 để tìm luồng tiếp theo
else i=tam; // còn không thì tiếp tục với vòng lặp kê tiếp
void nhap(int a[50][50],int n);
void xuat(int a[50][50],int n);
void luongcucdai(int a[50][50],int n);
// -//
void main()
{ clrscr();
printf("nhap so dinh n="); scanf("%d",&n);
printf("\n moi ban nhap ma tran cua do thi \n");
printf("\n CHU Y: tinh co HUONG cua do thi \n");
nhap(a,n);
/****************************************************
* Vi neu tu 1 dinh x qua thong qua dinh y thi dieu *
* nguoc lai la khong the.O day la nhap ma tran co *
Trang 28} }