1. Trang chủ
  2. » Luận Văn - Báo Cáo

Nhóm 1-5.Pdf

19 4 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Bài Tập Lớn Môn Học: Toán Rời Rạc
Tác giả Nguyễn Khôi Nguyên, Nguyễn Đức Lân, Nguyễn Trung Đức, Nguyễn Bá Phúc
Người hướng dẫn Dương Thị Thanh Tú
Trường học Học viện Công nghệ Bưu chính Viễn thông
Chuyên ngành Toán Rời Rạc
Thể loại Bài tập lớn
Năm xuất bản 2022
Thành phố Hà Nội
Định dạng
Số trang 19
Dung lượng 1,04 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

HỌC VIỆN CÔNG NGHỆ BƯU CHÍNH VIỄN THÔNG BÀI TẬP LỚN MÔN HỌC TOÁN RỜI RẠC NHÓM MÔN HỌC 02 Giảng viên Dương Thị Thanh Tú Sinh viên Nguyễn Khôi Nguyên Nguyễn Đức Lân Nguyễn Trung Đức Nguyễn Bá Phúc Nhóm[.]

Trang 1

HỌC VIỆN CÔNG NGHỆ BƯU CHÍNH VIỄN THÔNG

BÀI TẬP LỚN

MÔN HỌC: TOÁN RỜI RẠC NHÓM MÔN HỌC: 02

Giảng viên: Dương Thị Thanh Tú Sinh viên: Nguyễn Khôi Nguyên

Nhóm Bài tập lớn : 1_5

Hà Nội năm 2022

Trang 2

Chương I Giới thiệu và mục đích của đề tài 4

1 Giới thiệu đề tài 4

a Chu trình Euler(đồ thị Euler): 4

b Chu trình Hamilton(đồ thị Hamilton): 4

Chương II Kiến thức cơ sở 5

1 Đồ thị Euler 5

2 Thuật toán tìm chu trình Euler 5

2.1 Chứng minh đồ thị là Euler 6

2.2 Biểu diễn thuật toán tìm chu trình Euler 6

3 Đồ thị Hamilton 7

4 Thuật toán tìm tất cả các chu trình Hamilton 7

4.1 Chứng minh chu trình là Hamilton 7

4.2 Biểu diễn thuật toán tìm chu trình Hamilton 7

Chương III Ứng dụng 8

A Bài toán Người đưa thư 8

I - Phát biểu về bài toán người đưa thư 8

1 Phát biểu bài toán: 8

2 Cách giải: 8

II – Phương pháp giải và kiểm nghiệm 9

1 Phương pháp giải: 9

2 Kiểm nghiệm: 9

III –Chương trình 10

1 Bài toán người đưa thư 10

2 Cài đặt thuật toán 11

B Bài toán Người đi du lịch 16

I - Phát biểu về bài toán người đi du lịch 16

1 Phát biểu bài toán: 16

2 Cách giải: 16

II – Chương trình 16

1 Bài toán người đi du lịch 16

2.Cài đặt thuật toán 17

Trang 4

Chương I Giới thiệu và mục đích của đề tài

1 Giới thiệu đề tài

a Chu trình Euler(đồ thị Euler):

Là khái niệm xuất phát từ bài toán 7 cây cầu do Euler giải quyết vào khoảng năm

1737 Người dân trong thành phố đặt ra câu hỏi là thử tìm cách xuất phát từ một vùng đi,

đi qua tất cả 7 chiếc cầu, mỗi chiếc đi qua đúng 1 lần và trở về nơi xuất phát

đỉnh ứng với một vùng, mỗi cạnh ứng với một chiếc cầu

chu trình có dạng như mong muốn chỉ tồn tại khi và chỉ khi không có nút bậc lẻ Một đường

đi như vậy được gọi là một chu trình Euler

b Chu trình Hamilton(đồ thị Hamilton):

Khái niệm về đường đi và chu trình Hamilton được đưa ra bởi William Rowan Hamilton vào năm 1856, sau khi ô thiết kế một trò chơi trên khối đa diện 20 đỉnh, 30 cạnh,

12 mặt, mỗi mặt là một ngũ giác đều và người chơi cần chọn các cạnh để thành lập một đường đi qua 5 đỉnh cho trước(còn gọi là trò chơi Icosian)

Trang 5

Bài toán tổng quát được Hamilton đưa ra là: Tìm một chu trình đơn đi qua tất cả các đỉnh trên đồ thị, mỗi đỉnh đúng một lần sau đó quay trở về điểm xuất phát Cho đến nay, bài toán này vẫn chưa có lời giải đối với trường hợp đồ thị tổng quát Những bài toán liên quan tới chu trình Hamilton đều là những bài toán NP-hard Mọi thuật toán tìm kiếm chu trình Hamilton hiện nay đều chỉ thiết kế dựa trên mô hình duyệt mà thôi

2 Mục đích:

Giúp mọi người có thêm kiến thức về lý thuyết đô thị và hiểu hơn về đồ thị Euler

và Hamilton

Giúp giải quyết các bài toán ứng dụng

Chương II Kiến thức cơ sở

1 Đồ thị Euler

Định nghĩa:

- Chu trình đơn trong đồ thị G đi qua mỗi cạnh của đồ thị đúng một lần được gọi là chu trình Euler

- Đồ thị được gọi là đồ thị Euler nếu nó có chu trình Euler

2 Thuật toán tìm chu trình Euler

Để tìm một chu trình Euler của đồ thị ta sử dụng kết quả của định lý sau

Định lý 1 Điều kiện cần và đủ để đồ thị G=<V,E> là Euler Đồ thị vô hướng liên

thông G=<V, E> là đồ thị Euler khi và chỉ khi mọi đỉnh của G đều có bậc chẵn Đồ thị có hướng liên thông yếu G=<V, E> là đồ thị Euler khi và chỉ khi tất cả các đỉnh của nó đều

có bán đỉnh bậc ra bằng bán đỉnh bậc vào (điều này làm cho đồ thị là liên thông mạnh)

Trang 6

2.1 Chứng minh đồ thị là Euler

Đối với đồ thị vô hướng, để chứng minh đồ thi có là Euler hay không ta chỉ cần

thực hiện:

• Kiểm tra đồ thị có liên thông hay không? Điều này dễ dàng thực hiện bằng

cách kiểm tra DFS(u) = V hoặc BFS(u) = V thì ta kết luận đồ thị là liên thông

(u là đỉnh bất kỳ của đồ thị)

• Sử dụng tính chất của ma trận kề biểu đồ thị vô hướng để tính toán bậc của các đỉnh Đối với đồ thị có hướng, để chứng minh đồ thi có là Euler hay không ta chỉ cần

thực hiện:

• Kiểm tra đồ thị có liên thông yếu hay không? Điều này dễ dàng thực hiện bằng

cách kiểm tra nếu tồn tại đỉnh u V để DFS(u) = V hoặc BFS(u) = V thì ta kết luận đồ thị

là liên thông yếu

• Sử dụng tính chất của ma trận kề biểu đồ thị có hướng để tính bán đỉnh bậc ra

và bán đỉnh bậc vào của các đỉnh Bán đỉnh bậc ra của đỉnh u là deg+(u) là số

các số 1 của hàng u Bán đỉnh bậc vào của đỉnh u là deg-(u) là số các số 1 của

cột u

2.2 Biểu diễn thuật toán tìm chu trình Euler

Thuật toán Euler-Cycle(u):

Bước 1 (Khởi tạo) :

stack =;

CE =  ;

//Khởi tạo một stack bắt đầu là  //Khởi tạo mảng CE bắt đầu là  Push (stack, u) ; //Đưa đỉnh u vào ngăn xếp

Bước 2 (Lặp ):

while (stack ) do { //Lặp cho đến khi stack rỗng

s = get(stack); //Lấy đỉnh ở đầu ngăn xếp

if ( Ke(s)   ) then { // Nếu danh sách Ke(s) chưa rỗng

t =< Đỉnh đầu tiên trong Ke(s)>;

Push(stack, t)‟ //Đưa t vào stack;

E = E \ (s,t); // Loại bỏ cạnh (s,t);

}

else { //Trường hợp Ke(s)=

s = Pop(stack);// Đưa s ra khỏi ngăn xếp

Trang 7

s CE; //Đưa s sang CE

}

Bước 3 (Trả lại kết quả) :

<Lật ngược lại các đỉnh trong CE ta được chu trình Euler> ;

3 Đồ thị Hamilton

- Chu trình bắt đầu tại một đỉnh v nào đó đi qua tất cả các đỉnh còn lại mỗi đỉnh đúng một lần sau đó quay trở lại v được gọi là chu trình Hamilton

- Đồ thị có chu trình Hamilton được gọi là đồ thị Hamilton

4 Thuật toán tìm tất cả các chu trình Hamilton

Một số quy luật khi tìm chu trình Hamilton:

Cho đồ thị G=< V,E >

• 1.Nếu đỉnh v có bậc < 2: Không có chu trình Hamilton

• 2.Nếu đỉnh v có bậc = 2 thì cả 2 cạnh đều xuất hiện trong chu trình Hamilton

• 3.Khi đã chọn 2 cạnh nào đó của 1 đỉnh, xóa tất cả các cạnh còn lại

• 4.Nếu đỉnh v kề với > 2 đỉnh bậc 2 => Không có chu trình Hamilton

4.1 Chứng minh chu trình là Hamilton

Để tìm chu trình Hamilton của đồ thị ta có thể dựa vào các định lý sau

Định lý 1: Xét với đồ thị vô hướng G, trong đó tồn tại k đỉnh sao cho nếu xóa đi k

đỉnh này cùng với những cạnh liên thuộc của chúng thì đồ thị nhận được sẽ có nhiều hơn k thành phần liên thông Khi đó, khẳng định G không phải đồ thị Hamilton

Định lý 2: (Dirak,1952): Xét đơn đồ thị vô hướng G = (V, E) có n đỉnh (n ≥ 3) Nếu

mọi đỉnh đều có bậc không nhỏ hơn [n/2] thì G là đồ thị Hamilton

Định lý 3: (Ghouila – Houiri, 1960): Xét đơn đồ thị có hướng liên thông mạnh G =

(V, E) có n đỉnh Nếu trên phiên bản vô hướng của G, mọi đỉnh đều có bậc không nhỏ hơn n thì G là đồ thị Hamilton

Định lý 4: (Ore, 1960): Xét đơn đồ thị vô hướng G = (V, E) có n đỉnh (n ≥3) Xét

mọi cặp đỉnh không kề nhau, nếu không có cặp đỉnh nào tổng bậc nhỏ hơn n thì G

là đồ thị Hamilton

Định lý 5: (Meynie, 1973): Xét đơn đồ thị có hướng liên thông mạnh G = (V, E) có

n đỉnh Nếu trên phiên bản vô hướng của G, mọi cặp đỉnh không kề nhau đều có tổng bậc không nhỏ hơn 2n-1 thì G là đồ thị Hamilton

4.2 Biểu diễn thuật toán tìm chu trình Hamilton

Thuật toán liệt kê tất cả các chu trình Hamilton bắt đầu tại đỉnh thứ k

Trang 8

Hamilton(int k){

for(y ∈ Ke(X[k-1])){

if((k == n+1) && (y == v0))

Ghinhan(X[1],X[2],…,X[n], v0);

else if(chuaxet[y] == true){

X[k] = y;

chuaxet[y] = false;

Hamilton(k+1);

chuaxet[y] = true;

}

}

}

Khi đó, việc liên kết các chu trình Hamilton được thực hiện như sau:

Hamilton-Cycle(v0){

//Khởi tạo các đỉnh là chưa xét for(v ∈ V)

chuaxet[v] = true;

X[1] = v0; //v0 là một đỉnh nào đó của đồ thị

chuaxet[v0] = false; //Đánh dấu v0 đã xét

Hamilton(2); //Gọi thủ tục duyệt

}

Chương III Ứng dụng

A Bài toán Người đưa thư

I - Phát biểu về bài toán người đưa thư

1 Phát biểu bài toán:

MỘT NGƯỜI ĐƯA THƯ XUẤT PHÁT TỪ BƯU ĐIỆN PHẢI ĐẾN MỘT SỐ CON ĐƯỜNG ĐỂ PHÁT THƯ RỒI QUAY TRỞ VỀ ĐIỂM XUẤT PHÁT, HỎI

NGƯỜI ĐÓ PHẢI ĐI NHƯ THẾ NÀO ĐỂ SỐ ĐƯỜNG ĐI LÀ NGẮN NHẤT ?

2 Cách giải:

Ta xét bài toán ở một dạng đơn giản như sau :

Cho đồ thị vô hướng, liên thông có trọng số G<V, E> Một chu trình qua mọi cạnh của G gọi là một hành trình trong G Trong các hành trình đó, hãy tìm hành trình ngắn nhất

Trang 9

Rõ ràng nếu G là đồ thị Euler (mọi đỉnh đều có bậc chẵn) thì chu trình Euler trong

G (qua mỗi cạnh của G đúng một lần ) là hành trình ngắn nhất cần tìm

Chỉ còn phải xét trường hợp G có một số đỉnh bậc lẻ (số đỉnh bậc lẻ là một số chẵn) Khi đó, mọi hành trình trong G đi qua ít nhất 2 lần một số cạnh nào đó

3 Dữ liệu đầu vào

Biểu diễn đồ thị liên thông G bằng ma trận kề có trọng số Với các đỉnh không có cạnh nối thì giá trị là 0

II – Phương pháp giải và kiểm nghiệm

1 Phương pháp giải:

ĐỒ THỊ LIÊN THÔNG G VÔ HƯỚNG CÓ TRỌNG SỐ

Bước 1: Ktra trong đồ thị G có chu trình Euler hay ko? Nếu tồn tại thì chỉ cần tính tổng trọng số trong đồ thị(ta ko thể có một lộ trình ngắn hơn vì ta phải ghé thăm các đỉnh

ít nhất một lần) Ngược lại, nếu ko tồn tại chu trình Euler thì tiếp tục thực hiện Bước 2

Bước 2: Tìm tất cả đỉnh có bậc lẻ

Bước 3: Liệt kê tất cả các cặp đỉnh bậc lẻ có thể có (đối với n đỉnh bậc lẻ, tổng số các cặp có thể có là (n-1)*(n-3)*(n-5)…*1

Bước 4: Đối với mỗi cặp ghép nối, hãy tìm đường đi ngắn nhất nối chúng

Bước 5: Tìm các cặp mà đường đi nối chúng ngắn nhất là nhỏ nhất

Bước 6: Cập nhật các cạnh vừa tìm được ở bước 5 vào đồ thị G

Bước 7: Độ dài ngắn nhất chính là tổng trọng số trong đồ thị G mới

Bước 8: In ra mạch Euler của đồ thị đã sửa đổi

2 Kiểm nghiệm:

Trang 10

Bước 1: Xét đồ thị trên, có deg(a)=deg(b)=deg(f)=deg(e)=3(lẻ)

=> ko có chu trình Euler

Bước 2: Các đỉnh có bậc lẻ : A, B, E, F

Bước 3: Các cặp đỉnh bậc lẻ có thể có: [AE, BF], [AB, EF], [AF, BE]

Bước 4: Đường đi ngắn nhất nối các cặp đỉnh:

AE = AC + CE = 2+1 = 3

BF = BD + DF = 1+1 = 2

AB = 3

EF = 4

AF = AB+BD+DF = 5

BE = BA+AC+CE = 6 Bước 5: Cặp đỉnh có trọng số nhỏ nhất mà đi qua đỉnh bậc lẻ tìm được là [ae, bf] Bước 6: Cập nhật đồ thị, ưu tiên đi những cạnh có nhiều lần lặp lại trước

Bước 7: Độ dài đường đi ngắn nhất là 28

Bước 8: Đường đi tìm được :

A - C - E - A - B - D - F - B - D - F - E - C – A

III – Chương trình

1 Bài toán người đưa thư

Trang 11

2 Cài đặt thuật toán

#include<bits/stdc++.h>

using namespace std;

#define MAX 50

struct DoubleVertex{

int weight;

vector<int> path;

};

int V, len = 0;

int a[MAX][MAX];

vector<int> odd_vertex;

vector<int> cycle;

map<pair<int, int>, DoubleVertex> shortest_path;

vector<pair<int, int> > Set;

bool used[MAX]; int x[10];

int res = 1e9;

int deg[MAX];

int c[MAX][MAX];

// ham nhap gia tri

void nhap(void){

cin >> V;

cout<<"So dinh cua do thi n = "<< V <<endl;

// nhap ma trong so

cout << "Ma tran trong so cua do thi: \n";

for(int i=1; i<=V;i++)

{

6

0 3 1 0 5 0

3 0 0 1 0 6

1 0 0 0 2 0

0 1 0 0 0 1

5 0 2 0 0 4

0 6 0 1 4 0

28

1 3 5 1 2 4 6 2 4 6 5 3 1

Trang 12

for(int j=1; j<=V;j++)

{

cin >> a[i][j];

if(a[i][j] != 0)

c[i][j] = 1;

deg[i]++;

}

}

}

}

// ham phan hoach cac dinh bac le su dung quay lui hoan vi

void Try(int i){

if(i == odd_vertex.size()){

bool ok = true;

vector<pair<int, int> > tmp;

for(int k = 0; k < i; k += 2){

if(odd_vertex[x[k]] > odd_vertex[x[k + 1]]){

ok = false;

break;

} tmp.push_back({odd_vertex[x[k]], odd_vertex[x[k + 1]]}); }

if(ok){

for(int k = 0; k < tmp.size() - 1; k++){

if(tmp[k].first > tmp[k + 1].first){

ok = false;

break;

} }

if(ok){

int sum = 0;

for(int k = 0; k < tmp.size(); k++){

sum += shortest_path[tmp[k]].weight;

} if(sum < res){

res = sum;

Set = tmp;

}

Trang 13

} }

}

for(int j = 0; j < odd_vertex.size(); j++){

if(used[j] == false){

x[i] = j;

used[j] = true;

Try(i + 1);

used[j] = false;

} }

}

// kiem tra chu trinh Euler

bool checkEulerCycle(){

for(int i = 1; i <= V; i++){

if(deg[i] % 2){ //neu bac cua dinh la le thi deg[i]%2==true

odd_vertex.push_back(i);

} }

if(odd_vertex.size() == 0) return true; // khong co bac le nao thi return true else return false;

}

// ham tim chu trinh Euler va trong so

void EulerCycle(){

stack<int> st;

st.push(1);

while(!st.empty()){

int u = st.top();

int priority = 0;

int cnt = 0;

for(int i = 1; i <= V; i++){

if(c[u][i] > cnt){

priority = i;

cnt = c[u][i];

} }

if(cnt != 0){

Trang 14

len += a[u][priority];

st.push(priority);

c[u][priority] ; c[priority][u] ;

} else{

st.pop();

cycle.push_back(u);

} }

cout << "Do dai duong di ngan nhat la: " << len << endl;

reverse(cycle.begin(), cycle.end());

for(int i = 0; i < cycle.size(); i++){

cout << (char)(cycle[i]+'A'-1) << " ";

}

}

// ham tim duong di nho nhat tu dinh le den cac dinh con lai(thuat toan Dijkstra)

void shortestPath(int u){

int d[V + 1];

for(int i = 1; i <= V; i++){

d[i] = 1e9;

}

d[u] = 0;

int parent[V + 1];

parent[u] = u;

priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q; q.push({0, u});

while(!q.empty()){

pair<int, int> top = q.top();

q.pop();

int v = top.second;

int w = top.first;

if(w > d[v]) continue;

for(int i = 1; i <= V; i++){

if(a[v][i] != 0){

if(a[v][i] + d[v] < d[i]){

d[i] = d[v] + a[v][i];

q.push({d[i], i});

parent[i] = v;

Trang 15

} }

} }

for(int i = 1; i <= V; i++){

if(deg[i] % 2 == 1 && u < i){

vector<int> tmp;

int s = i;

while(s != u){

tmp.push_back(s);

s = parent[s];

} tmp.push_back(u);

reverse(tmp.begin(), tmp.end());

DoubleVertex x = {d[i], tmp};

shortest_path[{u, i}] = x;

} }

}

int main(){

memset(deg, 0, sizeof(deg));

memset(c, 0, sizeof(c));

nhap();

if(checkEulerCycle()){

EulerCycle();

}

else{

for(int i = 0; i < odd_vertex.size(); i++){

shortestPath(odd_vertex[i]);

} memset(used, false, sizeof(used));

Try(0);

for(int i = 0; i < Set.size(); i++){

vector<int> tmp = shortest_path[{Set[i].first, Set[i].second}].path;

for(int j = 0; j < tmp.size() - 1; j++){

c[tmp[j]][tmp[j + 1]]++;

c[tmp[j + 1]][tmp[j]]++;

}

Trang 16

} cout << endl;

EulerCycle();

}

}

B Bài toán Người đi du lịch

I - Phát biểu về bài toán người đi du lịch

1 Phát biểu bài toán:

MỘT NGƯỜI XUẤT PHÁT TỪ MỘT THÀNH PHỐ NÀO ĐÓ MUỐN TỚI THĂM N−1 THÀNH PHỐ KHÁC, MỖI THÀNH PHỐ ĐÚNG MỘT LẦN, RỒI QUAY

VỀ THÀNH PHỐ BAN ĐẦU HỎI NÊN ĐI THEO TRÌNH TỰ NÀO ĐỂ ĐỘ DÀI TỔNG CỘNG CÁC ĐOẠN ĐƯỜNG ĐI QUA LÀ NGẮN NHẤT

Bài toán Người du lịch chỉ là mô hình tiêu biểu của ứng dụng chu trình Hamilton Bài toán còn được hiểu là tìm chu trình Hamilton với độ dài đường đi nhỏ nhất

2 Cách giải:

Gọi C = { cij : i,j = 1,2, ,n} là ma trận chi phí

Mỗi hành trình: v = v(1)→v(2)→ →v(n-1)→v(n)→v(1) có thể viết dưới dạng:

v = (v(1),v(2)), (v(2),v(3)), , (v(n-1),v(n)), (v(n),v(1)) Trong đó, mỗi thành phần (v(i-1),v(i)) gọi là một cạnh của hành trình

Trong bài toán người du lịch khi tiến hành tìm kiếm lời giải ta sẽ phân tập hành trình thành hai tập con: Một tập chứa cạnh (i,j) và tập không chứa cạnh này Ta gọi việc

đó là phân nhánh, mỗi tập con nói trên gọi là nhánh

3 Dữ liệu đầu vào

Biểu diễn đồ thị liên thông G bằng ma trận kề có trọng số Với các đỉnh không có cạnh nối thì giá trị là 0

II – Chương trình

1 Bài toán người đi du lịch

5 7

1 2 3

2 3 7

5 3 5

4 3 6

5 4 2

So dinh: 5 So canh: 7

CHU TRINH HAMILTON LA: A B E C D A CHI PHI NHO NHAT LA: 20

Ngày đăng: 23/04/2023, 18:08

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN