You are on page 1of 8

TRƯỜNG ĐẠI HỌC BÁCH KHOA

KHOA: CÔNG NGHỆ THÔNG TIN


BỘ MÔN: CÔNG NGHỆ PHẦN MỀM

ĐỀ THI CUỐI KỲ
Tên học phần: TOÁN RỜI RẠC
Mã học phần: …………………… Số tín chỉ: 3
Phương pháp đánh giá (*): tự luận có giám sát Thời gian làm bài: 90 phút
Đề số: Đ0001
☐ Sinh viên được sử dụng tài liệu khi làm bài
----------------------------------------------------------------------------------------------------------------------------------
Họ tên: …………Nguyễn Hùng Phi…………… Lớp:………22T_DT2………MSSV:
………102220119……………...
Sinh viên làm bài trực tiếp trên tệp này, lưu tệp với định dạng MSSV_HọTên.pdf và nộp bài thông
qua MSTeam:
Câu 1 (3 điểm) Gọi Bn là số chuỗi độ dài n được hình thành từ các ký tự {A, B, C, 1, 2, 3, 4, 5, 6}.
a) Đếm số chuỗi Bn sao cho Bn chỉ chứa ký tự số.
# Trả lời: Trình bày và dán kết quả vào bên dưới:
Vì chuỗi B gồm n phần tử, mỗi phần tử là ký tự số => mỗi kí tự có 6 cách chọn =>
6^n

b) Lập hệ thức truy hồi để đếm số chuỗi Bn sao cho Bn không chứa hai ký tự số kề nhau.
# Trả lời: Trình bày cách xây dựng hệ thức truy hồi vào đây:
Gọi an số chuỗi Bn không chứa hai ký tự số kề nhau
-Trường hợp 1:bn {A,B,C}
-> bn có 3 khả năng xảy ra. Ứng với mỗi khả năng của bn thì số chuỗi Bn không chứa hai ký tự số kề
nhau bằng số chuỗi b1b2..bn-1 không chứa hai ký tự số kề nhau và bằng an-1.
Theo nguyên lý nhân thì số chuỗi Bn là: 3an-1
-Trường hợp 2: bn {1,2,3,4,5,6}: có 6 khả năng xảy ra cho bn
-> bn-1 {A,B,C} có 3 khả năng xảy ra cho bn-1-> có 6*3=18 khả năng xảy ra cho bn-1bn. Ứng với
mỗi khả năng của bn-1bn thì số chuỗi Bn không chưa hai ký tự số kề nhau bằng số chuỗi b1b2..bn-2 không
chứa hai ký tự số kề nhau và bằng an-2.
Theo nguyên lý nhân thì số chuỗi Bn là: 18an-2
Theo nguyên lý cộng ta có hệ thức truy hồi của an: an=3an-1+18an-2

#Trả lời: Xác định điều kiện ban đầu của hệ thức truy hồi vào đây:
Điều kiện ban đầu :
-Nếu n=1 thì: b1 có 9 khả năng xảy ra => a1=9
-Nếu n=2 thì:
+Nếu b2 {A,B,C} thì b1 có 9 khả năng xảy ra=> có 3*9=27 khả năng xảy ra của B2
+Nếu b2 {1,2,3,4,5,6} thì b1 có 3 khả năng xảy ra => có 6*3=18 khả năng xảy ra của B2
Theo nguyên lý cộng a2=27+18=45
Vậy a1=9,a2=45
c) Hãy giải hệ thức truy hồi trên câu b)
# Trả lời: Phương trình đặc trưng: x2=3x+18

# Trả lời: Nghiệm phương trình đặc trưng ( nếu có): x1 =6; x2 = -3

# Trả lời: Nghiệm tổng quát (nếu có):

# Trả lời: Nghiệm của hệ thức truy hồi (nếu có):

Vậy

Câu 2 ( 3 điểm) Cho tập X = {1, 2, …, n }, n∈ Z ,n ≥ 1.


a) Viết chương trình liệt kê tập con k phần tử từ X (k ∈ Z , 0≤ k ≤ n) sử dụng phương pháp sinh.
# Trả lời: Dán code vào đây:
#include <stdio.h>
#include <dos.h>
#include <conio.h>
#define MAX 20

int S[MAX], c=0, n, k;

void in();

int main()
{
int i,j;
printf("Nhap n>=k: ");
scanf("%d%d", &n, &k);

for (i=1; i<=k; i++)


S[i]=i;

in();

while (1) {
i=k;
while (i>0 && S[i]==n-k+i)
i--;
if (i==0)
break;
S[i]+=1;
for (j=i+1;j<=k;j++)
S[j]=S[j-1]+1;
in();
}

return 0;
}
void in()
{
int i;
printf("\n%3d: ",++c);
for (i=1; i<=k; i++)
printf("%d ", S[i]);
}
# Trả lời: Dán kết quả thực thi vào đây:

# Trả lời: Giải thích chi tiết cấu hình đầu tiên, cấu hình kết thúc, thuật toán sinh vào đây
Cấu hình đầu tiên được đặt là tập con có k phần tử đầu tiên của tập X, tức là {1, 2, ..., k}.
Cấu hình kết thúc là tập con cuối cùng có k phần tử của tập X. Trong thuật toán sinh, cấu hình kết thúc
được đặt là tập con có k phần tử cuối cùng của tập X, tức là {n-k+1, n-k+2, ..., n}.
Thuật toán sinh được sử dụng để liệt kê tất cả các tập con k phần tử của tập X bằng cách sinh ra tất cả các
tập con k phần tử bắt đầu từ cấu hình đầu tiên và kết thúc với cấu hình kết thúc. Thuật toán sinh được thực
hiện theo các bước sau:
 Bước 1: Khởi tạo cấu hình đầu tiên.
 Bước 2: In ra cấu hình hiện tại.
 Bước 3: Tìm vị trí j cuối cùng mà giá trị tại đó có thể được tăng lên.
 Bước 4: Nếu không tìm thấy vị trí j nào, kết thúc thuật toán.
 Bước 5: Tăng giá trị tại vị trí j lên một đơn vị.
 Bước 6: Với mỗi vị trí i lớn hơn j, đặt giá trị tại i bằng giá trị tại j cộng với i-j.
 Bước 7: Quay lại bước 2.

b) Viết chương trình liệt kê tất cả các tập con của X sử dụng kết quả ở câu a)
# Trả lời: Dán code vào đây:
#include <stdio.h>
#include <dos.h>
#include <conio.h>
#define MAX 20
int S[MAX],c,n, k;
void in();
main()
{
int i,j;
printf("nhap n:"); scanf("%d", &n);
for (k=1;k<=n;k++) {
c=0;
printf("\nTruong Hop K =%d:\n",k);
for (i=1; i<=k; i++)
S[i]=i;
in();
while (1){
i=k; while (i>0 && S[i]==n-k+i) i--;
if (i==0)
break;
S[i]+=1;
for (j=i+1;j<=k;j++)
S[j]=S[j-1]+1;
in();
}
}
}
void in()
{
int i;
printf("\n%3d: ",++c);
for (i=1; i<=k; i++) printf("%d ", S[i]);
}
# Trả lời: Dán kết quả vào đây với trường hợp n = 4:

Câu 3 (4 điểm) Cho đồ thị liên thông, có trọng số như sau:

B E
6
7
13 5
12
A G
3 D 14

5 2
16
15

C 25 F

a) Dùng thuật toán Dijkstra để tìm đường đi ngắn nhất từ đỉnh A đến đỉnh G.
# Trả lời: Trình bày cách giải bằng tay vào đây (yêu cầu trình bày dạng bảng):

1 A B C D E F G
2 0 , , , , , ,

3 * 12,A 5,A , , , ,

4 * 8,C * 7,C , 30,C ,

5 * 8,C * * 12,D 22,D ,

6 * * * * 12,D 22,D ,

7 * * * * * 22,D 19,E

8 * * * * * 22,D *

9 * * * * * * *

# Trả lời: chỉ nhất đường đi ngắn nhất


Đường đi ngắn nhất từ A – G : A->C->D->E->G
# Trả lời: độ đài đường đi ngắn nhất
Độ dài đường đi ngắn nhất từ A-G = 19

b) Viết chương trình sử dụng thuật Dijkstra để tìm đường đi ngắn nhất từ đỉnh A đến đỉnh G.
# Trả lời: Dán code ở đây:

# Trả lời: Dán kết quả thực thi với đầu vào đỉnh A, đỉnh G và ma trận trọng số:

# Trả lời: Giải thích chi tiết thuật toán Dijkstra:


Bước 1 : từ đỉnh gốc khởi tạo khoảng cách bằng 0 với chính nỏ khởi tạo khoảng cách tới các đỉnh ban đầu
là vô cùng ta được danh sách cách tới các đỉnh
Bước 2 : chọn đỉnh A có khoảng các nhỏ nhất trong danh sách này và ghi nhận . Các lần sau sẽ bỏ đỉnh
này ko duyệt tới
Bước 3 :lần lượt xét các đỉnh kề b của đỉnh a được chọn nếu khoảng cách từ gốc tới đỉnh b nhỏ hơn
khoảng cách hiện tại đang được ghi nhận thì cập nhật giá trị và đỉnh kề a và khoảng cách hiện tại của b
Bước 4 : sau khi xét tất cả các đỉnh kề b của đỉnh a thì lúc này ta được danh sách mới đã được cập nhật
quay lại bước 2 với danh sách này
Thuật toán kết thúc khi chọn được khoảng cách nhỏ nhất từ tất cả các điểm

c) Dùng thuật toán Kruskal để tìm cây khung nhỏ nhất của đồ thị.
# Trả lời: Trình bày cách làm bằng tay vào đây:

Trọng Số Các Cạnh


2 (C-D)
3 (C-B)
5 (D-E)
5 (A-C)
6 (B-E)
7 (E-G)
12 (A-B)
13 (B-D)
14 (E-F)
15 (D-F)
16 (F-G)
25 (C-F)

d) Viết chương trình sử dụng thuật Kruskal để tìm cây khung nhỏ nhất của đồ thị.
# Trả lời: Dán code ở đây:
#include <stdio.h>
#include <stdlib.h>

#define MAX 50

int n, m, minl, connect;


int dau[500], cuoi[500], w[500];
int daut[50], cuoit[50], father[50];

void Init(void) {
printf("Nhap so dinh va so canh cua do thi:\n");
scanf("%d%d", &n, &m);
printf("So dinh do thi: %d\n", n);
printf("So canh do thi: %d\n", m);
printf("Nhap danh sach cac canh va do dai cua chung:\n");
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &dau[i], &cuoi[i], &w[i]);
}
}

void Heap(int First, int Last) {


int j, k, t1, t2, t3;
j = First;
while (j <= (Last / 2)) {
if ((2 * j) < Last && w[2 * j + 1] < w[2 * j])
k = 2 * j + 1;
else
k = 2 * j;
if (w[k] < w[j]) {
t1 = dau[j];
t2 = cuoi[j];
t3 = w[j];
dau[j] = dau[k];
cuoi[j] = cuoi[k];
w[j] = w[k];
dau[k] = t1;
cuoi[k] = t2;
w[k] = t3;
j = k;
}
else
j = Last;
}
}

int tim(int i) {
int tro = i;
while (father[tro] > 0)
tro = father[tro];
return (tro);
}

void Union(int i, int j) {


int x = father[i] + father[j];
if (father[i] > father[j]) {
father[i] = j;
father[j] = x;
}
else {
father[j] = i;
father[i] = x;
}
}

void Kruskal(void) {
int last, u, v, r1, r2, ncanh, ndinh;
for (int i = 1; i <= n; i++)
father[i] = -1;
for (int i = m / 2; i > 0; i--)
Heap(i, m);
last = m;
ncanh = 0;
ndinh = 0;
minl = 0;
connect = 1;
while (ndinh < n - 1 && ncanh < m) {
ncanh = ncanh + 1;
u = dau[1];
v = cuoi[1];
r1 = tim(u);
r2 = tim(v);
if (r1 != r2) {
ndinh = ndinh + 1;
Union(r1, r2);
daut[ndinh] = u;
cuoit[ndinh] = v;
minl = minl + w[1];
}
dau[1] = dau[last];
cuoi[1] = cuoi[last];
w[1] = w[last];
last = last - 1;
Heap(1, last);
}
if (ndinh != n - 1)
connect = 0;
}

void Result(void) {
printf("Do dai cay khung nho nhat: %d\n", minl);
printf("Cac canh cua cay khung nho nhat:\n");
for (int i = 1; i < n; i++)
printf("%d %d\n", daut[i], cuoit[i]);
}

int main() {
Init();
Kruskal();
Result();
return 0;
}

# Trả lời: Dán kết quả thực thi ở đây:

# Trả lời: Giải thích chi tiết thuật toán Kruskal:


Sắp xếp các cạnh từ bé đến lớn theo trọng số . Lần lượt chọn các cạnh theo thứ tự từ bé đến lớn trong
danh sách sao cho không tạo thành 1 chu trình kính . thuật toán sẽ dừng lại khi đủ V -1 cạnh trong cây
khung với V là số lượng đỉnh của đồ thị .

Tổng cộng có: 3 câu


Đà Nẵng, ngày 08 tháng 05 năm 2023
GIẢNG VIÊN BIÊN SOẠN ĐỀ THI TRƯỞNG BỘ MÔN
(đã ký) (đã ký)

You might also like