Tải bản đầy đủ (.doc) (28 trang)

Báo cáo thực hành Toán rời rạc

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (124.55 KB, 28 trang )

Bài tập: TH Toán rời rạc

 

GVHD:Nguyễn Văn Nguyên

MỤ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

SV:Trần Thanh Liêm--------------Lớp: 07T2----------------------------------- Trang: 1


Bài tập: TH Toán rời rạc

 


GVHD:Nguyễn Văn Nguyên

LỜ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ế.

SV:Trần Thanh Liêm--------------Lớp: 07T2----------------------------------- Trang: 2


Bài tập: TH Toán rời rạc

 

GVHD:Nguyễn Văn Nguyên

Phần I
Bài toán liệt kê

SV:Trần Thanh Liêm--------------Lớp: 07T2----------------------------------- Trang: 3



 

Bài tập: TH Toán rời rạc

GVHD:Nguyễn Văn Nguyên

Bà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.)
int j;
for(j=0;j<=1;j++)
{ s[i]=j;
if(i==n)
{ switch (chon)
{
case 1: in();

break;
case 2: not2bit0(); break;
case 3: two_bit0(); break;
}
}
else lietke(i+1,chon);
}

Với lệnh swicth….case để chọn các hàm in tương ứng đã giới hạn điều kiện theo đề

Chương trình
/* CHUONG TRINH DEM SO XAU NHI PHAN voi do dai n */
#include<conio.h>

SV:Trần Thanh Liêm--------------Lớp: 07T2----------------------------------- Trang: 4


Bài tập: TH Toán rời rạc

 

GVHD:Nguyễn Văn Nguyên

#include<stdio.h>
#include<dos.h>
void lietke(int i,int chon);
void in();
void not2bit0();
void two_bit0();
int s[50],n,d=0;

//-----------------------------------//
void main()
{ clrscr();
printf(" 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");
d=0;
lietke(1,3);
getch();
}
//-----------------------------------//
void lietke(int i,int chon)
{
int j;
for(j=0;j<=1;j++)
{ s[i]=j;
if(i==n)
{ switch (chon)
{ case 1: in();
break;
case 2: not2bit0(); break;

case 3: two_bit0(); break;
}
}
else lietke(i+1,chon);
}
}
//------------------------------------//
void in()
{ int i;
d++;
printf("\n%3d: ",d);
for(i=1;i<=n;i++)
printf("%2d",s[i]);
}
//------------------------------------//
//----Ham tim cac xau ko co 2 bit 0 ke nhau----//
void not2bit0()
{
int i,kt=1;
for(i=1;i<=n-1;i++)

SV:Trần Thanh Liêm--------------Lớp: 07T2----------------------------------- Trang: 5


Bài tập: TH Toán rời rạc

 

GVHD:Nguyễn Văn Nguyên


if(s[i]==0&&s[i+1]==0) kt=0;
if(kt) in();
}
//------------------------------------//
//----Ham tim cac xau CO 2 bit 0 ke nhau----//
void two_bit0()
{
int i,kt=0;
for(i=1;i<=n-1;i++)
if(s[i]==0&&s[i+1]==0) kt=1;
if(kt) in();
}

Bài 3:
Viế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ử.
Đoạn code
do
{
dem++;
printf("\n %5ld:",dem); puts(s);
i = n - 2;

while (i >=0 && s[i] >= s[i+1]) i--;

if (i >= 0)
{
k = n - 1;

while (s[k] <= s[i]) k--;
hoanvi(s[i],s[k]);
int a = i + 1;
int b = n - 1;
while (a < b)
{
hoanvi(s[a],s[b]);
a++;
b--;
}
}
}
while (i >= 0);

SV:Trần Thanh Liêm--------------Lớp: 07T2----------------------------------- Trang: 6


Bài tập: TH Toán rời rạc

 

GVHD:Nguyễn Văn Nguyên

Chương trình
/* Chuong trinh liet ke cac xau chu ( hoan vi lap ) */
#include<conio.h>

#include<stdio.h>
#include<string.h>
#include<dos.h>
int n,d;
//---------------------------------//
void 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);
long gt(long n);
void lietke(char *s,int n);
//---------------------------------//
void main()
{ clrscr();
char *a,*s,*b;
int i,k;
long t;
printf(" Nhap 1 xau ky tu: \n"); gets(s);
printf(">---> Xau ban vua nhap la:"); puts(s);
n=strlen(s);
printf(">---> Do dai xau ky tu la:%d\n",n);
xauchuan(s,n);
puts(s);
phantu(s,a,n,k);
printf("\n>---> so loai phan tu gom %d loai \n",k);
t=hoanvilap(a,n,k);
printf(">---> tong so xau la : %ld\n",t);
delay(2000);
lietke(s,n);
getch();

}
//---------------------------------//
void xauchuan(char *s,int n)
{ int i,j,tam;
for(i=0;ifor(j=i+1;jif( *(s+i) >= *(s+j) )
hoanvi(*(s+i),*(s+j));
}
//---------------------------------//
void hoanvi(char &a,char &b)
{ int tam;
tam=a;
a=b;
b=tam;
}
//--------------------------------//
void phantu(char *s,char *a,int n,int &k)
{ int i,j=0,tam;
tam=*(s+0);
k=1;

SV:Trần Thanh Liêm--------------Lớp: 07T2----------------------------------- Trang: 7


Bài tập: TH Toán rời rạc

 

GVHD:Nguyễn Văn Nguyên


*(a+0)=0;
for(i=1;ifor(i=0;iif (tam!= *(s+i) )
{ k++;
tam= *(s+i);
j++;
}
else *(a+j)+=1;
for(i=0;i}
//---------------------------------//
long hoanvilap(char *a,int n,int k)
{
int i;
long t;
t=gt(n);
for(i=0;it/=gt(*(a+i));
return t;
}
//---------------------------------//
long gt(long n)
{ if(n<=1) return 1;
n*=gt(n-1);
return n;
}
//---------------------------------//
void lietke(char *s,int n)

{ long dem = 0 , i , j, k;
for (i = 0;i < n - 1;i++)
for (j = i + 1;j < n;j++)
if (s[i] > s[j]) hoanvi(s[i],s[j]);
do
{
dem++;
printf("\n %5ld:",dem); puts(s);
i = n - 2;
while (i >=0 && s[i] >= s[i+1]) i--;
if (i >= 0)
{
k = n - 1;
while (s[k] <= s[i]) k--;
hoanvi(s[i],s[k]);
int a = i + 1;
int b = n - 1;
while (a < b)
{
hoanvi(s[a],s[b]);
a++;
b--;
}
}
}
while (i >= 0);
}

SV:Trần Thanh Liêm--------------Lớp: 07T2----------------------------------- Trang: 8



Bài tập: TH Toán rời rạc

 

GVHD:Nguyễn Văn Nguyên

//---------------------------------//

Bà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
void thu(int i)
{ int j;
for(j=0;j<=k;j++)
{
s[i]=j;
if(i==n) in();
else thu(i+1);
}
}

Với hàm kiểm tra là hàm in() để giới hạn điều kiện theo đề bài

void in()
{ int i,t=0,ok=1;
for(i=1;i<=n;i++)
t+=s[i];
if(t!=k) ok=0;
if(ok)
{
d++;
printf("\n%5ld: ",d);
for(i=1;i<=n;i++) printf("%2d",s[i]);
}
}

Chương trình
/* CHUONG TRINH LIET KE NGHIEM CUA PT */
/*
x(1)+x(2)+.......+x(n)=k
*/
#include<conio.h>
#include<stdio.h>
#include<dos.h>
//--------------------------------------//

SV:Trần Thanh Liêm--------------Lớp: 07T2----------------------------------- Trang: 9


Bài tập: TH Toán rời rạc

 


GVHD:Nguyễn Văn Nguyên

int a[10],s[10],n,k;
long d=0;
//--------------------------------------//
void thu(int i);
void in();
//--------------------------------------//
void main()
{ clrscr();
int i;
do{
printf("so phan tu X la: n=");scanf("%d",&n);
printf("Tong cua pt la: k=");scanf("%d",&k);
}while( n>k || n<0 || k<0 );
delay(1000);
for(i=1;i<=k;i++) a[i]=1;
thu(1);
printf("\n Tong nghiem la :%ld",d);
getch();
}
//----------ham liet ke----------------//
void thu(int i)
{ int j;
for(j=0;j<=k;j++)
{
s[i]=j;
if(i==n) in();
else thu(i+1);
}

}
//-----------ham in va kiem tra--------//
void in()
{ int i,t=0,ok=1;
for(i=1;i<=n;i++)
t+=s[i];
if(t!=k) ok=0;
if(ok)
{
d++;
printf("\n%5ld: ",d);
for(i=1;i<=n;i++) printf("%2d",s[i]);
}
}

SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 10


Bài tập: TH Toán rời rạc

 

GVHD:Nguyễn Văn Nguyên

SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 11


Bài tập: TH Toán rời rạc

 


GVHD:Nguyễn Văn Nguyên

Phầ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
SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 12


 

Bài tập: TH Toán rời rạc

GVHD:Nguyễn Văn Nguyê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
- In ra kết quả

Chương trình

#include <stdio.h>
#include <conio.h>
#define max 100
int n,thoi_gian1[max],thoi_gian2[max];
void nhap();
void thuchien();
//--------------MAIN-------------------//
void main()
{
clrscr();
nhap();
thuchien();
getch();
}
//------------------------------------//
void nhap()
{
int i;
printf("So chi tiet : ");
scanf("%d", &n);
for (i=0;i{
printf("\nThoi gian gia cong chi tiet [%d] tren may A : ", i+1);
scanf("%d", &thoi_gian1[i]);
printf("\nThoi gian gia cong chi tiet [%d] tren may B : ", i+1);
scanf("%d", &thoi_gian2[i]);
}
// In thong tin nhan duoc
printf("\n\n may A : ");
for (i=0;i

printf("%5d", thoi_gian1[i]);
printf("\n\n may B : ");
for (i=0;iprintf("%5d", thoi_gian2[i]);
}
//-----------------------------------------//
void thuchien()
{ int thoi_gian=0,i;
for (i=0;i{
if(thoi_gian1[i]else thoi_gian+=thoi_gian2[i];
}
printf("\n\nThoi gian hoan thanh nhanh nhat: %d",thoi_gian);
}

SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 13


 

Bài tập: TH Toán rời rạc

GVHD:Nguyễn Văn Nguyên

Bài 2:
Viết chương trình nhập n là số thành phố và nhập ma trận khoảng
cách Cnxn=(cij)nxn.Tìm hành trình ngắn nhất của người du lịch.

Chương trình

/* Chuong trinh bai toan nguoi du lich */
#include<conio.h>
#include<stdio.h>
#include<math.h>
//------------------------------------//
int n, b[20], c[20][20], count=0;
int a[20],xopt[20];
int can, cmin,fopt;
int min_khoangcach();
//-----------------------------------//
void dulieu();
void init();
void print();
void hoandoi();
void kyluc();
void thu(int i);
void xuatmt(int c[20][20],int n);
//-----------------------------------//
void main()
{ clrscr();
printf("Nhap du lieu cho bai toan\n");
dulieu();
init();
thu(2);
print();
getch();
}
//------------------------------------//
void dulieu()
{ int i,j;

printf("So thanh pho n=");scanf("%d",&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{if(i!=j && i{
printf("\nEnter khoang cach giua cac thanh pho(<=32767 )%d va %d:",i,j);
scanf("%d",&c[i][j]);
}
if(c[i][j]==0) c[i][j]=32767;
c[j][i]=c[i][j];
c[i][i]=0;
}
printf("\n ma tran khoang cach\n");

SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 14


Bài tập: TH Toán rời rạc
}

 

GVHD:Nguyễn Văn Nguyên

xuatmt(c,n);

//------------------------------------//
int min_khoangcach()
//Tim gia tri nho nhat cua ma tran khong nam tren duong cheo chinh
{ int i,j, min=2000;

for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i!=j && min>c[i][j]) min=c[i][j];
return(min);
}
//-----------------------------------//
void init()
{ int i;
cmin=min_khoangcach();
fopt=32000;
can=0;
a[1]=1;
for(i=1;i<=n;i++) b[i]=1;
}
//-----------------------------------//
void print()
{ int i;
printf("\n Hanh trinh toi uu %d",fopt);
printf("\nHanh trinh: ");
for(i=1;i<=n;i++)
{
printf("%3d",xopt[i]);
}
printf("%3d",1);
}
//-----------------------------------//
void hoandoi()
{ int i;
for(i=1;i<=n;i++)
xopt[i]=a[i];

}
//-----------------------------------//
void kyluc()
{ int sum;
sum=can+c[a[n]][a[1]];
if(sum{ hoandoi();
fopt=sum;
}
}
//-----------------------------------//
void thu(int i)
{ int j;
for(j=2;j<=n;j++)
{ if(b[j])
{ a[i]=j;
b[j]=0;
can=can+c[a[i-1]][a[i]];
if(i==n) kyluc();

SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 15


Bài tập: TH Toán rời rạc

 

GVHD:Nguyễn Văn Nguyên

else if(can+(n-i+1)*cmin

{ count++;
thu(i+1);
}
b[j]=1;
can=can-c[a[i-1]][a[i]];
}

}

}
void xuatmt(int c[20][20],int n)
{
int i,j;
for(i=1;i<=n;i++)
{printf("\n");
for(j=1;j<=n;j++)
printf("%5d",c[i][j]);
}
}

SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 16


Bài tập: TH Toán rời rạc

 

GVHD:Nguyễn Văn Nguyên

Phần III:

Bài toán trên đồ thị

SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 17


 

Bài tập: TH Toán rời rạc

GVHD:Nguyễn Văn Nguyên

Bà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 ( a ij=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.

Thuật toán
Hàm nhập ma trận kề trọng số Anxn=(aij)nxn của đồ
thị vô hướng liên thông G gồm n đỉnh bằng hàm random(100) .
randomize();
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{ if(i==j) a[i][j]=0;
else a[i][j]= random(100);

}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=a[j][i];

Kiểm tra Euler
Nếu có quá 2 đỉnh có bậc là bậc lẽ thì ko phải đồ thị Euler
int i,j,dem=0,kt=0;
for(i=1;i<=n;i++)
{ for(j=1;j<=n;j++)
if(a[i][j]!=0)
dem++;
if( (dem%2)!=0) kt++;
dem=0;
}
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

SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 18


Bài tập: TH Toán rời rạc

 


GVHD:Nguyễn Văn Nguyên

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ó
4) Đoạn code
void prim()
{ int i,j,dinh,min,phu,k;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
if(a[i][j] == 0) // nếu cạnh nào bằng 0 thì gán bằng MAX tức qui ước là vô cùng ( 32000)
a[i][j]=MAX;
b[i]=MAX;// b để chứa các giá trị đỉnh rìa
}
min=MAX; // nạp cho min = MAX
dinh=1; //khởi tạo tại đỉnh 1
for(i=1;i{ for(j=1;j<=n;j++)
if(a[dinh][j] < b[j] ) // nếu cạnh đó bé hơn giá trị tương ứng của phần tử mãng b thì nạp giá trị đó vào
b[j]=a[dinh][j];
for(k=1;k<=n;k++)// tìm giá trị nhỏ nhất của mãng b
{ printf(" %6d",b[k]);
if(b[k] < min)
{
min=b[k];
phu=k;// tìm đc đỉnh k là đỉnh đi tiếp theo
}
a[dinh][phu]=MAX;//khi đã đi qua thì gán cạnh đã đi qua là vô cùng

a[phu][dinh]=MAX;
}
b[phu]=MAX;//khi nạp được cho min thì xác lập lại bằng vô cùng
printf("\n min=%3d",min); // in giá trị min
printf("\n");
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
SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 19


Bài tập: TH Toán rời rạc

 

GVHD:Nguyễn Văn Nguyên

4) Đoạn code

void dijkstra()
{ int v,u,minp;
printf("\nTim duong di tu s=");scanf("%d",&s);
printf(" den ");scanf("%d",&t);
for(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
{ minp=32000;//gan minp=vô cùng
//tìm đỉnh rìa u với đỉnh t(cuối) có trọng số nhỏ nhất
for(v=1;v<=n;v++)
{ if(!final[v] && minp>d[v])
{
u=v;//có thể v=t
minp=d[v];
}
}
final[u]=1; //đánh dấu đỉnh u đã được dùng
if(!final[t])//t#v(đỉnh t chưa dùng)
{ for(v=1;v<=n;v++)
{ if((!final[v]) && (d[u]+cp[u][v]{
d[v]=d[u]+cp[u][v];
truoc[v]=u;//nạp u vào ma trận tìm đường đi
}

}
}
}
}

Chương trình
/* chuong trinh tim khung cay phu(prim)*/
/*
duong di ngan nhat(Dijkstra) */
#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
#include<dos.h>
#define MAX 32000
//---------------------------------------//
int a[50][50],dem,n,b[50];
int s,t;
char chon;
int truoc[100],d[100],cp[100][100];
int final[100];
//---------------------------------------//
void nhap();
void xuat();

SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 20


Bài tập: TH Toán rời rạc

 


GVHD:Nguyễn Văn Nguyên

void prim();
void euler();
void dijkstra();
void print();
//--------------------------------------//
void main()
{ clrscr();
printf("Nhap so dinh cua ma tran n=");
scanf("%d",&n);
printf("\n -------> voi gia tri 32000 la qui uoc cho vo cung \n");
nhap();
xuat();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cp[i][j]=a[i][j];
euler();
delay(2000);
printf("\n tim khung cay phu nho nhat ( PRIM )\n");
prim();
printf("\n>----> Trong so cay phu nho nhat la :%d\n",dem);
delay(2000);
printf("\n tim duong di ngan nhat ( DIJKSTRA )\n");
dijkstra();
print();
getch();
}
//---------nhap Random----------//

void nhap()
{ int i,j;
randomize();
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{ if(i==j) a[i][j]=0;
else a[i][j]= random(100);
}
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
a[i][j]=a[j][i];
}
//---------xuat-----------------//
void xuat()
{ int i,j;
for(i=1;i<=n;i++)
{ printf("\n\n");
for(j=1;j<=n;j++)
printf("%6d",a[i][j]);
printf("\n");
}
}
//-----Kiem tra Euler---------//
void euler()
{ int i,j,dem=0,kt=0;
for(i=1;i<=n;i++)
{ for(j=1;j<=n;j++)
if(a[i][j]!=0)
dem++;


SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 21


Bài tập: TH Toán rời rạc

 

GVHD:Nguyễn Văn Nguyên

if( (dem%2)!=0) kt++;
dem=0;
}
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-------------//
void prim()
{ int i,j,dinh,min,phu,k;
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
if(a[i][j] == 0)
a[i][j]=MAX;
b[i]=MAX;
}

min=MAX;
dinh=1;

for(i=1;i{ for(j=1;j<=n;j++)
if(a[dinh][j] < b[j] )
b[j]=a[dinh][j];
for(k=1;k<=n;k++)
{ printf(" %6d",b[k]);
if(b[k] < min)
{
min=b[k];
phu=k;
}
a[dinh][phu]=MAX;
a[phu][dinh]=MAX;
}
b[phu]=MAX;
printf("\n min=%3d",min);
printf("\n");
dinh=phu;
if(min!=MAX) dem+=min;
min=MAX;
}
}
//---------------------------//
void print()
{ int i,j;
printf("\nDuong di ngan nhat tu %d den %d la\n",s,t);
printf("%d<=",t);
i=truoc[t];
while(i!=s)
{printf("%d<=",i);

i=truoc[i];
}
printf("%d",s);
printf("\nDo dai duong di la %d",d[t]);

SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 22


Bài tập: TH Toán rời rạc

 

GVHD:Nguyễn Văn Nguyên

}
//-------Ham dijkstra--------//
void dijkstra()
{ int v,u,minp;
printf("\nTim duong di tu s=");scanf("%d",&s);
printf(" den ");scanf("%d",&t);
for(v=1;v<=n;v++)
{d[v]=cp[s][v];
truoc[v]=s;
final[v]=0;
}
truoc[s]=0;
d[s]=0;
final[s]=0;
while(!final[t])
{minp=2000;

for(v=1;v<=n;v++)
{ if(!final[v] && minp>d[v])
{ u=v;
minp=d[v];
}
}
final[u]=1; //u la dinh co nhan tam thoi nho nhat
if(!final[t])
{ for(v=1;v<=n;v++)
{ if((!final[v]) && (d[u]+cp[u][v]{
d[v]=d[u]+cp[u][v];
truoc[v]=u;
}
}
}
}
}
//------------------------//

SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 23


Bài tập: TH Toán rời rạc

 

GVHD:Nguyễn Văn Nguyên

Phần IV:

Bà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
==============
Viết chương trình nhập n là số đỉnh và nhập ma trận khoảng cách
khả năng thông qua của các cung Cnxn=(cij)nxn với quy ước đỉnh v1 là
đỉnh nguồn và vn là đỉnh đích.Dùng thuật toán Ford-Fulkerson để
tìm luồng cực đại trên mạng đã nhập.

Thuật toán
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
là không thể,vì có hướng từ x đến y, (aji)=0.

SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 24


Bài tập: TH Toán rời rạc

 

GVHD:Nguyễn Văn Nguyên

b) Vì đỉnh 1 là nguồn nên không thể từ các đỉnh khác có khả năng thông qua
đỉnh 1, (ai 1)=0 với i=1..n.
c) Vì đỉnh n là đích nên từ đỉnh n không thể tới được các đỉnh khác, (an i)=0
với i=1..n.
d) 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
scanf("%d",&a[i][j]);
} while( a[j][i]!=0 );

qua la:",i,j);

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(ok)
{ tam=i; // gời giá trị đỉnh i của vòng lặp
for(j=1;j<=n;j++)
if( a[i][j])

{
c[k]=j; // chứa các đỉnh của đường tăng luồng
b[k]=a[i][j]; // nạp các giá trị thông qua của cạnh ij
phu=k; // lưu lại số đỉnh của luồng
k++;
i=j; // gán đỉnh đến là j thành đỉnh khởi đầu lại vòng lặp tiếp theo tìm cạnh kê tiếp
j=1;// khởi đầu vòng lặp lại với j=1
}
min=b[1];// tìm giá trị nhõ nhất của các khả năng thông qua các cạnh trong đường tăng luồng này
for(h=1;hif( 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

SV:Trần Thanh Liêm--------------Lớp: 07T2-----------------------------------Trang: 25


×