Professional Documents
Culture Documents
3/1/2009
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
MỤC LỤC
Chương 5: Cây bao trùm nhỏ nhất & Thuật toán Kruskal .............................................................................................. 16
2
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
3
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
Cài đặt danh sách cạnh bằng danh sách liên kết:
4
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
Hoặc:
5
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
Tổ chức dữ liệu
Để biểu diễn ma trận, ta dùng một mảng hai chiều kiểu nguyên.
#define MAX 100
struct GRAPH {
int n;
int a[MAX][MAX];
};
Đọc ma trận kề từ tập tin vào mảng
void ReadGraph(GRAPH &g, char *fn) {
// mở file, nếu không mở được file sẽ báo lỗi và thoát
FILE * f = fopen(fn, “rt”);
if (f == NULL) {
exit(0);
}
// đọc giá trị đỉnh của đồ thị vào biến n
fscanf(f, “%d”, &g.n);
// đọc giá trị của ma trận a từ file
int i, j;
for (i=0; i<g.n; i++)
for (j=0; j<g.n; j++)
fscanf(f, “%d”, &g.a[i][j]);
// đóng file nhập
fclose(f);
}
Xuất ma trận kề ra màn hình
void PrintGraph(GRAPH &g) {
// in ra số đỉnh của đồ thị
printf(“%d\n”, g.n);
for (int i=0; i<g.n; i++) {
for (int j=0; j<g.n; j++)
printf(“%d\t”, g.a[i][j]);
printf(“\n”);
}
}
2. CÀI ĐẶT DANH SÁCH CẠNH VÀ DANH SÁCH KỀ
Xem như bài tập
6
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
7
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
8
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
// 1, 2, … là đã duyệt và đỉnh thuộc miền liên thông tương ứng
int visited[MAX];
int nconnect;
void solve(GRAPH& g) {
// khởi tạo nhãn cho tất cả các đỉnh là chưa duyệt
// đặt số miền liên thông ban đầu la 0
nconnect = 0;
for (int i=0; i<g.n; i++)
visited[i] = 0;
// lặp để tìm đỉnh chưa xét, gọi hàm visit cho đỉnh này
9
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
4. Một chuyên gia tin học muốn viết một chương trình xác đ ịnh số đối tượng trong một
tấm ảnh nhị phân. Một đối tượng được xác định gồm các điểm đen liên thông bốn với
nhau trong ma trận ảnh. Hãy giúp chuyên gia tin học đếm số đối tượng này.
Dữ liệu: Dữ liệu vào từ file văn bản BITMAP.INP
- Dòng đầu tiên ghi 2 số tự nhiên N và M (1 < N, M <=250) tương ứng số lượng
chiều dài và chiều rộng của tấm ảnh.
- Dòng thứ I trong N dòng tiếp theo chứa M số nhị phân 0 (trắng) hoặc 1 (đen).
Kết quả: Kết quả ghi ra file văn bản BITMAP.OUT như sau:
BITMAP.INP BITMAP.OUT
55 4
10 0 0 1
10 0 1 1
11 0 1 1
10 1 0 0
10 0 1 1
5. Một cơ quan có N nhân viên được đánh số thứ tự từ 1 đến N. Mỗi người có một phòng
làm việc riêng của mình . Do nhu cầu công việc , hằng ngày mỗi nhân viên có thể phải
tiếp xúc với một số nhân viên khác . Vào một ngày làm việc bình thường , có một nhân
viên bị nhiễm SARS , nhưng do không biết nên người này vẫn đi làm . Đến cuối ngày
làm việc người ta mới phát hiện ra người nhiễm bệnh SARS đầu tiên . Khả năng lây
lan của SARS rất nhanh chóng : một người nhiễm bệnh SARS nếu tiếp xúc với một
người khác có thể sẽ truyền bệnh cho người này.
Yêu cầu: Hãy giúp các bác sĩ kiểm tra xem cuối ngày hôm đó , có bao nhiêu người có
thể nhiễm bệnh và đó là những người nào để còn cách ly . Người có tiếp xúc với người
nhiễm bệnh được coi là người nhiễm bệnh
Dữ liệu: Dữ liệu vào từ file văn bản SARS.INP
10
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
- Dòng đầu tiên ghi 2 số tự nhiên N và K (1 < N <=250, 1<=K<=N) tương ứng số
lượng người làm việc trong tòa nhà và số hiệu của nhân viên đã nhiễn SARS đ ầu
tiên.
- Dòng thứ I trong N dòng tiếp theo ghi danh sách n hững người có tiếp xúc với
người thứ I theo cách sau : số đầu tiên J của dòng là tổng số nhân viên đã gặp
người thứ I, tiếp theo là J số tự nhiên lần lượt là số hiệ u của các nhân viên đó . Nếu
J=0 có nghĩa là không ai đã tiếp xúc với người I
Kết quả: Kết quả ghi ra file văn bản SARS.OUT như sau:
- Dòng đầu tiên ghi số S là tổng số người có thể bị lây nhiễm SARS
- Dòng thứ 2 liệt kê tất cả các người có thể bị lây nhiễm SARS cần cách ly , danh
sách cần được sắp xếp theo thứ tự tăng dần của số hiệu nhân viên
Trong các file dữ liệu và kết quả , các số trên cùng một dòng cách nhau ít nhất một
dấu cách.
Ví dụ:
SARS.INP SARS.OUT
51 3
223 123
213
12
15
14
11
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
12
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
Dữ liệu nhập vào từ tập tin văn bản DUONGHAM.IN gồm:
• Dòng đầu chứ 3 số nguyên dương n (n<=50), D, C (D, C là dòng và c ột của phòng
trung tâm).
• N dòng tiếp theo, mỗi dòng chứa n số là các số ở các vị trí tương ứng trên hoạ đồ.
Kết quả tìm được ghi ra tập tin văn bản DUONGHAM.OUT. Dòng đầu chứa số m là
số ô phải đi qua, nếu không thoát được thì m=-1. Trong trường hợp thoát được, m
dòng tiếp theo, m dòng tiếp theo: mỗi dòng chứa 2 số là số hiệu dòng cột của các ô
phải đi qua theo đúng trình tự của một cách thoát hiểm.
Ví dụ:
DUONGHAM.IN DUONGHAM.OUT
4 2 1 3
0 1 1 0 2 1
1 0 0 1 2 2
1 1 1 1 3 2
0 1 1 0
13
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
14
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
T.a[i][j] = 1; T.a[j][i] = 1;
visited[j] = 1;
n++;
}
}
III. BÀI TẬP
1. Viết chương trình đ ọc ma trận kề của đồ thị vô hướng G từ tập tin GRAPH.INP, cho
biết đồ thị G có liên thông hay không? Nếu có hãy tìm ra một cây bao trùm nhỏ nhất
của G và in ra file GRAPH.OUT các cạnh của cây bao trùm này.
2. Viết chương trình th ực hiện yêu cầu của câu 1 với cách cài đặt tối ưu bằng cách sử
dụng PriorityQueue.
15
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
Chương 5: Cây bao trùm nhỏ nhất & Thuật toán Kruskal
Bước 2: Sắp xếp lại các cạnh theo thứ tự trọng số tăng dần.
Bước 3: Khởi tạo nhãn root, với root[i] = i (root[i] biểu diễn đỉnh gốc của i
trong cây chứa i)
Bước 4: Chọn ra cạnh e = (x,y) nhỏ nhất chưa duyệt trong danh sách cạnh.
Nếu không có một cạnh e nào như thế, dừng thuật toán thất bại
Bước 5: Đánh dấu cạnh e là đã duyệt. Nếu nhãn của root[e.x] và root[e.y]
giống nhau (nghĩa là chúng thuộc cùng miền liên thông, việc chọn cạnh e sẽ
làm phát sinh chu trình), quay lại bước 4.
Bước 6: Cập nhật cạnh e vào cây bao trùm, nếu số cạnh đã chọn n-1, dừng
thuật toán thành công! Cập nhật tất cả các đỉnh có root là root[e.y] thành
root[e.x].
Quay lại bước 4.
16
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
int rj = j; while (root[rj] != -1) rj = root[rj];
if (ri != rj) {
io = i; jo = j;
rio = ri; rjo = rj;
break;
}
k++;
} while (k < ne);
n++;
T.a[i][j] = T.a[j][i] = g.a[i][j];
root[rj] = ri;
}
17
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
Xem lại thuật toán kiểm tra miền liên thông chúng ta đã làm, việc kiểm tra xem có tồn
tại một đường đi (kể cả có hướng và vô hướng) từ đỉnh x đến đỉnh y hay không hoàn
toàn có thể làm được với hàm viếng duyệt. Tuy nhiên nếu muốn chỉ ra một đường đi
cụ thể, ta phải thực hiện lại việc lưu vết (lưu đỉnh cha).
Để tìm đường trong đồ thị, ta có thể sử dụng phương pháp duyệt đồ thị theo chiều sâu
hoặc phương pháp duyệt đồ thị theo chiều rộng. Về cơ bản, hai phương pháp này có
thể xem là tương tự nhau (đồng thời tương tự phương pháp duyệt tìm thành phần liên
thông đã nêu ở chương 2). Nếu cài đặt bằng phương pháp khử đệ quy, điểm khác biệt
giữa hai phương pháp này là cấu trúc dữ liệu được sử dụng. Duyệt theo chiều sâu sử
dụng STACK còn duyệt theo chiều rộng sử dụng QUEUE.
18
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
stackcount++;
// gán đường đi cho j
previous[j] = i;
…
}
}
}
…
// duyệt tất cả các đỉnh trong hàng đợi
while (queueindex < queuecount)
{
// lấy đỉnh x từ hàng đợi
x = queue[queueindex];
queueindex++;
// xét tất cả đỉnh j chưa được duyệt và có nối với x
for (j…)
if (…)
{
// đưa j vào hàng đợi
queue[queuecount] = j;
queuecount++;
// gán đường đi cho j
previous[j] = i;
…
}
}
}
19
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
20
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
for (mỗi đỉnh v thuộc G) {
D[v] = C(s, v);
}
D[s] = 0;
while ( (V-S) != Φ ) {
Chọn đỉnh u thuộc (V-S) sao cho D[u] ngắn nhất;
S = S U {u};
for ( mỗi v thuộc (V-S) ) {
if (D[u] + C(u, v) < D[v]) {
D[v] = D[u] + C(u, v);
}
}
}
21
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
22
Bài tập thực hành lý thuyết đồ thị Khoa CNTT-TUD, ĐH Tôn Đức Thắng
1. Cài đặt thuật toán Floyd
2. Cho đồ thị vô hướng G liên thông. Tìm một đỉnh sao cho đường đi dài nhất từ vị trí đó
tới các đỉnh còn lại là ngắn nhất.
3. Cho 1 điểm O và n điểm trong mặt phẳng tọa độ. Từ n điểm đó, xây 1 hàng rào bao
quanh điểm O sao cho chu vi hàng rào là nhỏ nhất. (O không nằm trên cạnh của hàng
rào).
23