Mơ tả bài toánTrò chơi Line là trò chơi di chuyển các viên bi trong một hình vuông 9 x 9 ô.Bi được ăn khi tạo thành các hàng, cột, đường chéo gồm 5 viên bi liên tiếp cùngmàu.. Một thuật
Trang 1BỘ GIÁO DỤC VÀ ĐÀO TẠO
TRƯỜNG ĐẠI HỌC NHA TRANG
KHOA CÔNG NGHỆ THÔNG TIN
—————————————–
BÁO CÁO BÀI TẬP PROJECT
MÔN HỌC: TRÍ TUỆ NHÂN TẠO
Trang 2MỤC LỤC
I Bài tập cài đặt thuật toán 3
1 Bài tập về thuật toán BFS (Line3_BFS.cpp) 3
a Mô tả bài toán 3
b Giải thích code và cách giải 4
c Độ phức tạp giải thuật 7
2 Bài toán TSP (TSP.cpp) 8
a Mô tả bài toán 8
b Giải thích code và cách giải 8
c Độ phức tạp giải thuật 10
3 Bài toán tô màu đồ thị (toMauDoThi.cpp) 11
a Mô tả bài toán 11
b Giải thích code và cách giải 11
c Độ phức tạp giải thuật 13
4 Bài toán bốc sỏi (bocsoi.cpp) 13
a Mô tả bài toán 13
b Giải thích code và cách giải 14
c Độ phức tạp giải thuật 15
II Bài tập thực hành trên lớp 15
1 Đổi tiền (doitien.cpp) 15
a Mô tả bài toán 15
b Giải thích code và cách giải 16
c Độ phức tạp giải thuật 16
2 Trò chơi tictactoe (tictactoe.cpp) 17
a Mô tả bài toán 17
b Giải thích code và cách giải 17
c Độ phức tạp giải thuật 19
3 Puzzle (Puzzle.cpp) 20
a Mô tả 20
b Giải thích code và cách giải 20
c Độ phức tạp giải thuật 23
4 Tìm số nguyên tố lớn nhất (timSoNTMax.cpp) 24
a Mô tả bài toán 24
b Giải thích code và cách giải 24
Trang 3c Độ phức tạp thuật toán 25
5 Xây d ng máy ch IIS làm server multimedia cho video H.264, music mp3 ự ủ 26
a T ng quan vềề IIS server ổ 26
b Các bước thực hiện 26
6 Cài đ t Ubuntu ch y trền nềền windows ặ ạ 29
7 Thiềết l p m ng lan truy c p máy ch t xa qua kềết nốếi ssh ậ ạ ậ ủ ừ 33
a. T ng quan vềề SSHổ 33
b T ng quan vềề SSH ổ 33
c Xây d ng máy ch FTP ự ủ 37
8 S d ng Toolkit multimedia ffmpeg, ffplay th c hi n cống vi c ử ụ ự ệ ệ 41
III.Kềết Lu n ậ 43
TÀI LIỆU THAM KHẢO 44
Trang 4I Bài tập cài đặt thuật toán
1 Bài tập về thuật toán BFS (Line3_BFS.cpp)
a Mô tả bài toán
Trò chơi Line là trò chơi di chuyển các viên bi trong một hình vuông 9 x 9 ô
Bi được ăn khi tạo thành các hàng, cột, đường chéo gồm 5 viên bi liên tiếp cùngmàu
Một thuật toán được sử dụng trong trò chơi là tìm đường đi để di chuyển mộtviên bi Giả sử trò chơi Line tổng quát có n dòng, n cột Đánh số các dòng từ 1 đến
n theo thứ tự từ trên xuống dưới, đánh số các cột từ 1 đến n theo thứ tự từ trái sangphải Giả sử có một viên bi tại ô (y, x) – dòng y cột x, bi có thể di chuyển đến 1trong 4 ô (y+1, x), (y-1, x), (y, x+1), (y, x-1), nếu ô đó đang trống Cho vị trí bắtđầu và vị trí kết thúc của viên bi, hãy viết chương trình cho biết đường
đi ngắn nhất của viên bi (qua ít ô nhất)
Dòng thứ nhất gồm năm số n, sy, sx, dy, dx, mỗi số cách nhau một khoảng trắng (2 ≤ n ≤ 30; 1 ≤ sy, sx, dy, dx ≤ n) sy là chỉ số dòng, sx là chỉ số cột của viên bi cần di chuyển dy là chỉ số dòng, dx là chỉ số cột của vị trí cần di
chuyển viên bi đến
Trang 5 Trong n dòng tiếp theo, mỗi dòng gồm n số nguyên 0 hoặc 1, mỗi số cách
nhau một khoảng trắng, biểu thị tình trạng của trò chơi Số 1 nghĩa là vị trí ô
đó có bi, số 0 nghĩa là vị trí ô đó đang trống
(Dữ liệu cho bảo đảm tại ô (sy, sx) có giá trị là 1, tại ô (dy, dx) có giá trị là 0)
Dữ liệu xuất:
Nếu tìm được đường đi ngắn nhất:
Dòng đầu tiên in ra số nguyên m là chiều dài (số ô) của đường đi (bao gồm
cả ô đầu tiên của viên bi và ô đích)
Trong m dòng tiếp theo, dòng thứ I in ra hai giá trị yi, xi là vị trí ô thứ I trongđường đi, hai số cách nhau một khoảng trắng
(Nếu có nhiều đường đi cùng ngắn nhất, chỉ cần in ra một đường đi bất kỳ)
Nếu không tìm được đường đi: in ra 0
b Giải thích code và cách giải
Để giải quyết bài toán trò chơi Line, ta sử dụng thuật toán tìm đường đi ngắnnhất trong một ma trận Dưới đây là phần giải thích chi tiết về cách code hoạtđộng:
Khai báo cấu trúc Point để đại diện cho một ô trên ma trận Mỗi Point có haithuộc tính y và x lưu trữ tọa độ dòng và cột của ô tương ứng
Bool isValidMove( int y, int x, int n)
vector<Point> findShortestPath(vector<vector< int >> & board, Point start, Point end)
{
Trang 6int n = board.size();
vector<vector< bool >> visited(n, vector< bool >(n, false ));
vector<vector<Point>> parent(n, vector<Point>(n, {- 1 , - 1 }));
int ny = current.y + dy[i];
int nx = current.x + dx[i];
if (isValidMove(ny, nx, n) && !visited[ny][nx] && board[ny][nx] == 0 ) {
Trang 7Khởi tạo ma trận visited và parent để lưu trạng thái đã được thăm và tọa độcha của mỗi ô.
Đưa ô start vào hàng đợi q và đánh dấu ô này là đã thăm
Duyệt qua hàng đợi q cho đến khi nó trống:
Lấy ra ô đầu tiên từ hàng đợi và gán cho current
Kiểm tra nếu current là ô đích (end), thì truy vết từ end đến start để lấyđường đi và trả về đường đi đó
Duyệt qua các ô kề của current (4 hướng: lên, xuống, trái, phải):
Kiểm tra xem ô kề có hợp lệ (nằm trong ma trận và không có viên bi) vàchưa được thăm
Nếu hợp lệ, đưa ô kề vào hàng đợi, đánh dấu là đã thăm và ghi nhận current
là cha của ô kề đó
Nếu không tìm thấy đường đi, trả về một vector rỗng
Trong hàm main(), đầu tiên đọc các dữ liệu đầu vào: kích thước ma trận n,tọa độ ô bắt đầu sy và sx, tọa độ ô đích dy và dx Sau đó, đọc ma trận board từ đầuvào
Int main()
{
int n, sy, sx, dy, dx;
cin >> n >> sy >> sx >> dy >> dx;
vector<vector< int >> board(n, vector< int >(n));
for ( int I = 0 ; I < n; i++)
Point start = {sy – 1 , sx – 1 };
Point end = {dy – 1 , dx – 1 };
vector<Point> path = findShortestPath(board, start, end);
Trang 8cout << path[i].y + 1 << “ “ << path[i].x + 1 << endl;
Tạo điểm bắt đầu start và điểm đích end dựa trên tọa độ đầu vào
Gọi hàm findShortestPath() để tìm đường đi ngắn nhất từ start đến end trênboard Lưu kết quả vào vector path
Kiểm tra nếu path rỗng, tức là không tìm được đường đi, in ra 0 Ngược lại,
in ra độ dài của đường đi m và các tọa độ của các ô trên đường đi
Duyệt qua tất cả các ô trên ma trận, có độ phức tạp O(n^2)
Mỗi ô sẽ được thêm vào hàng đợi q một lần và được duyệt qua một lần, có
Vì vậy, độ phức tạp của BFS trong trường hợp xấu nhất là O(n^2)
Sau khi tìm được đường đi, ta truy vết từ ô đích đến ô bắt đầu để lấy đường đi.Truy vết có độ phức tạp O(m), với m là số ô không phải là viên bi trên đường đi
Tổng kết lại, độ phức tạp của thuật toán trên là O(n^2 + m) Trong trườnghợp tốt nhất, khi ô đích được tìm thấy ngay từ ô bắt đầu, độ phức tạp là O(n^2).Trong trường hợp xấu nhất, khi không tìm thấy đường đi hoặc đường đi là đườngdài nhất, độ phức tạp là O(n^2 + m)
Trang 92 Bài toán TSP (TSP.cpp)
a Mô tả bài toán
Bài toán TSP (Traveling Salesman Problem) là một bài toán quan trọngtrong lý thuyết đồ thị và được áp dụng rộng rãi trong thực tế Bài toán đặt ra câuhỏi: "Làm thế nào để một người bán hàng đi qua tất cả các thành phố một lần vàquay trở lại thành phố xuất phát, sao cho khoảng cách di chuyển là ngắn nhất?"
Bài toán TSP được mô hình hóa dưới dạng một đồ thị đơn vô hướng, trong
đó các đỉnh đại diện cho các thành phố và các cạnh đại diện cho khoảng cách giữacác thành phố Mục tiêu của bài toán là tìm một chu trình Hamiltonian (một chutrình đi qua tất cả các đỉnh đúng một lần) có chi phí nhỏ nhất
Bài toán TSP là một bài toán tối ưu hóa tổ hợp NP-khó, có nghĩa là không cógiải thuật đa thức thời gian để giải quyết bài toán cho tất cả các trường hợp Do đó,các giải thuật heuristic và phương pháp tìm kiếm cục bộ thường được sử dụng đểgiải quyết bài toán TSP
Các ứng dụng của bài toán TSP rất đa dạng, bao gồm lập kế hoạch giaohàng, lập lịch sản xuất, tối ưu hóa quỹ đạo máy bay, tối ưu hóa tuyến đường vậntải, và nhiều ứng dụng khác trong kinh doanh và khoa học
b Giải thích code và cách giải
Để giải quyết bài toán TSP (Traveling Salesman Problem) ta có thể sử dụngphương pháp Branch and Bound (nhánh cận) Bài toán TSP đặt ra câu hỏi: Nếu cómột người bán hàng phải đi qua tất cả các thành phố để bán hàng và quay trở lạithành phố ban đầu, thì hãy tìm chu trình ngắn nhất mà anh ta có thể thực hiện
Dưới đây là cách mà code hoạt động:
INF được sử dụng để biểu diễn một giá trị vô cùng, thường được sử dụng để
so sánh với các giá trị khác để tìm giá trị nhỏ nhất
const int INF = 1e9 ;
Biến toàn cục:
int n; // S l ố ượ ng đ nh trong đ th ỉ ồ ị
int graph[ 20 ][ 20 ]; // Ma tr n tr ng s c a đ th (t i đa 20 đ nh) ậ ọ ố ủ ồ ị ố ỉ
vector< int > path; // Chu trình Hamiltonian t m th i ạ ờ
vector< int > best_path; // Chu trình Hamiltonian t t nh t ố ấ
Trang 10 n là số lượng đỉnh trong đồ thị.
graph là ma trận trọng số của đồ thị, thể hiện khoảng cách giữa các đỉnh
path là một vector để lưu trữ chu trình Hamiltonian tạm thời
best_path lưu trữ chu trình Hamiltonian tốt nhất tìm thấy
best_cost lưu trữ chi phí của chu trình Hamiltonian tốt nhất
Hàm isSafe:
bool isSafe( int v, int pos, vector< bool > visited, int cost_so_far) {
// Ki m tra xem có c nh n i đ nh cu i c a chu trình t m th i và v hay không ể ạ ố ỉ ố ủ ạ ờ
Kiểm tra xem đỉnh v đã được thăm chưa
Kiểm tra xem nếu thêm chi phí từ đỉnh trước đó tới v vượt quá best_cost thì cónên thêm v vào chu trình tạm thời không
Hàm TSP_BranchAndBound:
void TSP_BranchAndBound( int pos, vector< bool > visited, int cost_so_far) {
// N u đã đi qua t t c các đ nh, thì ki m tra xem có t o thành chu trình ế ấ ả ỉ ể ạ Hamiltonian hay không
Trang 11for ( int v = 0 ; v < n; v++) { // Thay đ i t v = 1 thành v = 0 ổ ừ
if (isSafe(v, pos, visited, cost_so_far)) {
Đây là hàm chính để tìm chu trình Hamiltonian tốt nhất
Nếu đã đi qua tất cả các đỉnh, thì kiểm tra xem có tạo thành chu trìnhHamiltonian hay không và cập nhật kết quả tốt nhất nếu cần
Duyệt qua tất cả các đỉnh còn lại để thử thêm vào chu trình tạm thời
Hàm main:
Nhập số lượng đỉnh n và ma trận trọng số graph
Nhập đỉnh xuất phát starting_vertex
Khởi tạo biến và chu trình tạm thời
Gọi hàm TSP_BranchAndBound để tìm chu trình tốt nhất
In kết quả: chu trình tốt nhất, chi phí và đỉnh xuất phát
Chương trình này sử dụng phương pháp Branch and Bound để tối ưu hóa việcduyệt qua tất cả các đỉnh để tìm chu trình Hamiltonian tốt nhất
Trang 12 Đây là hàm quan trọng thực hiện tìm kiếm và thu thập thông tin về chu trìnhHamiltonian tốt nhất.
Trong trường hợp tốt nhất, thuật toán có thể tìm thấy một chu trình Hamiltonianngay từ đầu, mất O(1) thời gian
Trong trường hợp xấu nhất, thuật toán phải thử tất cả các khả năng(backtracking) để tìm ra chu trình Hamiltonian tốt nhất Điều này có thể xảy rakhi đồ thị rất lớn và không có các giới hạn dừng sớm Trong trường hợp này, độphức tạp sẽ là O(n!), với n là số lượng đỉnh
Hàm main:
Nhập ma trận trọng số có độ phức tạp là O(n^2), với n là số lượng đỉnh
Gọi hàm TSP_BranchAndBound có độ phức tạp tùy thuộc vào thời gian mất đểtìm chu trình tốt nhất
Tổng cộng, độ phức tạp của giải thuật này có thể được xấp xỉ là O(n!) trongtrường hợp xấu nhất Tuy nhiên, giải thuật thường được cải tiến và kết hợp với cáccách thức để giảm số lượng các trường hợp được thử, như cắt tỉa (pruning), để tối
ưu hóa thời gian chạy thực tế
3 Bài toán tô màu đồ thị (toMauDoThi.cpp)
a Mô tả bài toán
Bài toán tô màu đồ thị là một bài toán trong lĩnh vực lý thuyết đồ thị và tối
ưu hóa mà tác vụ chính là gán một tập màu cho các đỉnh trong đồ thị sao chokhông có hai đỉnh kề nhau có cùng màu Mục tiêu là tìm cách tô màu tối ưu saocho số màu sử dụng là nhỏ nhất
b Giải thích code và cách giải
Đây là một chương trình C++ để tô màu đồ thị bằng thuật toán BFS Thuậttoán này sử dụng một hàng đợi để lưu trữ các đỉnh của đồ thị và duyệt qua các đỉnhtheo chiều rộng, tô màu cho từng đỉnh trong quá trình duyệt
Mã nguồn bao gồm các phần sau:
Khai báo các biến và thư viện:
numNodes: số lượng đỉnh trong đồ thị
numEdges: số lượng cạnh trong đồ thị
Trang 13 graph: một vector chứa danh sách kề của các đỉnh trong đồ thị.
colors: một vector chứa màu của từng đỉnh trong đồ thị
startNode: đỉnh bắt đầu để tô màu
visited: một vector chứa trạng thái của các đỉnh đã được thăm hay chưa
nodeQueue: một hàng đợi để lưu trữ các đỉnh trong quá trình duyệt đồ thị.Hàm colorGraph:
void colorGraph(vector<vector< int >> & graph, vector< int > colors, int startNode) {
int numNodes = graph.size();
vector< bool > visited(numNodes, false );
queue< int > nodeQueue;
// Gán màu cho đ nh hàng xóm ch a đ ỉ ư ượ c tô màu
for ( int color = 1 ; color <= numNodes; color++) {
bool isColorAvailable = true ;
for ( int adj : graph[neighbor]) {
Duyệt qua các đỉnh của đồ thị bắt đầu từ đỉnh startNode
Tại mỗi đỉnh, kiểm tra các đỉnh hàng xóm và gán màu cho đỉnh hàng xómchưa được tô màu
Trang 14 Nếu đỉnh hàng xóm đã được tô màu, kiểm tra xem màu đã được dùng haychưa Nếu đã dùng, thử một màu khác.
Hàm main:
Nhập số lượng đỉnh và số lượng cạnh của đồ thị từ người dùng
Nhập các cạnh của đồ thị và lưu chúng vào graph
Nhập đỉnh bắt đầu để tô màu
Gọi hàm colorGraph để tô màu đồ thị
In ra kết quả của màu của từng đỉnh
Thuật toán tô màu BFS được sử dụng để tô màu đồ thị bằng cách duyệt quacác đỉnh theo chiều rộng Khi tô màu cho một đỉnh, thuật toán sẽ kiểm tra các đỉnhhàng xóm và gán màu cho đỉnh hàng xóm chưa được tô màu Nếu đỉnh hàng xóm
đã được tô màu, thuật toán sẽ kiểm tra xem màu đã được dùng hay chưa Nếu đãdùng, thử một màu khác Quá trình này được lặp lại cho tất cả các đỉnh trong đồthị
Vì vậy, độ phức tạp của giải thuật tô màu đồ thị bằng BFS trong chươngtrình này là O(V+E), với một số trường hợp xấu nhất có độ phức tạp là O(V^2)
4 Bài toán bốc sỏi (bocsoi.cpp)
a Mô tả bài toán
Trò chơi Bốc Sỏi, còn được gọi là trò chơi Nim, là một trò chơi hai ngườichơi, trong đó mỗi người lần lượt bốc một số lượng sỏi từ các đống sỏi, và ngườichơi cuối cùng còn lại đóng vai trò là người thua
Trang 15Trò chơi này có thể chơi với số lượng đống sỏi và số lượng sỏi trong mỗiđống khác nhau Trong mỗi lượt, người chơi có thể bốc bất kỳ số lượng sỏi từ mộtđống sỏi nào đó Điều quan trọng là người chơi phải bốc ít nhất một viên sỏi.
Ví dụ, nếu có 3 đống sỏi với số lượng sỏi lần lượt là 3, 5 và 7, người chơi cóthể bốc bất kỳ số lượng sỏi từ bất kỳ đống sỏi nào, nhưng phải bốc ít nhất một viênsỏi Người chơi cuối cùng còn lại đóng vai trò là người thua
Trò chơi Bốc Sỏi là một trò chơi rất thú vị và có ứng dụng rộng rãi trong lýthuyết trò chơi và thông tin Nó được sử dụng để giải quyết nhiều vấn đề trong toánhọc, bao gồm cả các vấn đề tối ưu và lý thuyết đồ thị
b Giải thích code và cách giải
Khởi tạo đống sỏi ban đầu:
Mảng piles được khởi tạo với số lượng sỏi trong mỗi đống ban đầu
Trong ví dụ của bạn: piles[0] = 5, piles[1] = 4, và piles[2] = 7
Vòng lặp chính (While loop):
Chương trình bắt đầu một vòng lặp vô hạn để chơi trò chơi cho đến khi mộtngười chơi thua
Hiển thị trạng thái đống sỏi:
Hàm displayPiles được gọi để hiển thị trạng thái hiện tại của các đống sỏi
Lấy lựa chọn từ người chơi:
Người chơi được yêu cầu chọn một trong các đống sỏi
Sau đó, họ cũng được yêu cầu chọn số lượng sỏi muốn lấy khỏi đống đãchọn
Cập nhật trạng thái đống sỏi:
Số lượng sỏi mà người chơi đã chọn bị loại bỏ khỏi đống sỏi tương ứng bằngcách giảm giá trị của piles[selectedPile] đi stonesToRemove
Kiểm tra điều kiện thua:
Sau khi mỗi nước đi của người chơi, chương trình kiểm tra xem tất cả cácđống sỏi có trống hết hay không
Nếu tất cả đống đều trống (không còn sỏi), chương trình thông báo ngườichơi đã thua và vòng lặp kết thúc
Lặp lại vòng lặp:
Chương trình quay lại bước 3 và tiếp tục vòng lặp cho đến khi một ngườichơi thua
Ví dụ:
Người chơi chọn đống 2 và lấy 2 sỏi Đống 2 sẽ trở thành "O O"
Người chơi chọn đống 3 và lấy 4 sỏi Đống 3 sẽ trở thành "O O O O"
Trang 16Người chơi chọn đống 1 và lấy 3 sỏi Đống 1 sẽ trở thành "O".
c Độ phức tạp giải thuật
Vòng lặp chính (While loop):
Vòng lặp chính sẽ chạy cho đến khi có người chơi thua, điều này xảy ra khitất cả đống sỏi đã trống
Độ phức tạp: O(N), trong đó N là tổng số sỏi ban đầu
Hiển thị trạng thái đống sỏi:
Hiển thị trạng thái các đống sỏi, số lượng sỏi trong mỗi đống
Độ phức tạp: O(N), với N là số lượng đống sỏi
Lấy lựa chọn từ người chơi:
Nhập lựa chọn của người chơi và số lượng sỏi muốn lấy
Độ phức tạp: O(1), vì việc nhập có thể coi là hằng số
Cập nhật trạng thái đống sỏi:
Giảm giá trị của phần tử trong mảng piles để thể hiện việc loại bỏ sỏi
Độ phức tạp: O(1), vì chỉ là việc gán giá trị mới cho mảng
Kiểm tra điều kiện thua:
Lặp qua tất cả các đống để kiểm tra xem có đống nào còn sỏi hay không
Độ phức tạp: O(N), với N là số lượng đống sỏi
Vậy tổng cộng, độ phức tạp chính của mã nguồn trò chơi bốc sỏi này làO(N), với N là tổng số lượng sỏi ban đầu và số lượng đống sỏi Điều này có nghĩa
là độ phức tạp của chương trình tương ứng với kích thước của dữ liệu đầu vào
Trang 17II Bài tập thực hành trên lớp
1 Đổi tiền (doitien.cpp)
a Mô tả bài toán
Bài toán đổi tiền là một bài toán thực tế và phổ biến, mà chúng ta thường gặp trongcuộc sống hàng ngày Bài toán này đặt ra câu hỏi: "Nếu bạn có một số tiền cần trảlại và một loạt các đồng tiền khác nhau, bạn có thể trả lại số tiền đó bằng cách sửdụng ít đồng tiền nhất?"
Khai báo một vector result để lưu trữ các đồng tiền cần trả lại
Khai báo biến coinIndex để lưu chỉ số của đồng tiền mà chúng ta đang xét, bắtđầu từ đồng tiền lớn nhất
Vòng lặp while:
Trong khi amount còn lớn hơn 0 và coinIndex còn lớn hơn hoặc bằng 0 (chưaxét hết các đồng tiền)
Kiểm tra nếu mệnh giá của đồng tiền tại coinIndex nhỏ hơn hoặc bằng amount
Nếu điều kiện đúng, chúng ta trừ amount bằng mệnh giá của đồng tiền này vàthêm nó vào vector result
Nếu điều kiện sai, chúng ta chuyển sang đồng tiền nhỏ hơn bằng cách giảm giátrị của coinIndex
Hàm main:
Đầu vào: amount và coins đã được khai báo
Gọi hàm greedyCoinChange để tìm cách trả lại số tiền amount bằng cách sửdụng các đồng tiền từ coins
Trang 18 Hiển thị số lượng đồng tiền cần trả lại và danh sách đồng tiền bằng phương thứccủa vector change.
Với đầu vào là amount = 47 và coins = {10, 5, 1}, kết quả sẽ là 8 đồng tiền (10
đó N là số tiền cần đổi
Trong một số trường hợp đặc biệt, bài toán đổi tiền có thể trở nên phức tạp hơn, ví
dụ như khi có các đồng tiền không phải là bội số của nhau hoặc có ràng buộc phứctạp khác
2 Trò chơi tictactoe (tictactoe.cpp)
a Mô tả bài toán
Trò chơi Tic Tac Toe (còn gọi là X-O) là một trò chơi giữa hai người chơi,trong đó họ thay phiên nhau đặt các ký hiệu của họ (X hoặc O) vào một lưới 3x3.Mục tiêu của trò chơi là tạo được một dãy liên tiếp gồm ba ký hiệu của mình (theohàng ngang, hàng dọc hoặc đường chéo), hoặc điền hết bảng mà không có ai thắng.Trò chơi kết thúc khi một người chơi thắng hoặc hết bàn cờ
b Giải thích code và cách giải
void drawBoard( const std::vector<std::vector< char >> & board) {
for ( int i = 0 ; i < 3 ; ++i) {
Trang 19Hàm drawBoard được sử dụng để vẽ bàn cờ Tic Tac Toe Nó duyệt quamảng 2D board và in ra các ký hiệu 'X', 'O' hoặc khoảng trắng để tạo ra bàn cờ.Dấu | và - được dùng để vẽ đường phân chia giữa các hàng và các cột
bool checkWin( const std::vector<std::vector< char >> & board, char symbol) {
for ( int i = 0 ; i < 3 ; ++i) {
if (board[i][ 0 ] == symbol && board[i][ 1 ] == symbol && board[i][ 2 ] == symbol) {
int main() {
std::vector<std::vector< char >> board( 3 , std::vector< char >( 3 , ' ' )); // Bàn
c 3x3 ờ
char currentPlayer = 'X' ; // Ng ườ i ch i hi n t i ơ ệ ạ
std::cout << "Chao mung den voi tictactoe!" << std::endl;
for ( int move = 0 ; move < 9 ; ++move) {
drawBoard(board);
int row, col;
std::cout << "Nguoi choi " << currentPlayer << ", nhap hang va cot 2): " ;
Trang 20std::cin >> row >> col;
if (row < 0 || row > 2 || col < 0 || col > 2 || board[row][col] != ' ' ) {
std::cout << "Lua chon khong hop le, chon lai!" << std::endl;
if (!checkWin(board, 'X' ) && !checkWin(board, 'O' )) {
std::cout << "Hoa!" << std::endl;
}
return ;
}
Trong hàm main:
Khởi tạo board, một mảng 2D 3x3, đại diện cho bàn cờ Tic Tac Toe
Khai báo biến currentPlayer để lưu người chơi hiện tại (là 'X' hoặc 'O')
Trong vòng lặp for, mỗi lượt chơi sẽ vẽ bàn cờ, cho phép người chơi chọn vị trí
và kiểm tra thắng thua hoặc hòa
Nếu người chơi đã thắng, chương trình hiển thị bàn cờ và thông báo người chơithắng
Cuối cùng, nếu không có người chơi nào thắng và bàn cờ đã được điền đầy,chương trình thông báo hòa
c Độ phức tạp giải thuật
Để phân tích độ phức tạp của thuật toán trong mã nguồn trò chơi Tic TacToe, chúng ta sẽ xem xét từng phần của chương trình và xác định độ phức tạpcủa chúng theo thời gian Trong phân tích này, chúng ta sẽ sử dụng ký hiệuO(lớn hơn) để biểu thị độ phức tạp tối đa
Trang 21Khởi tạo bàn cờ (9 ô) và một số biến như currentPlayer và move.
Vòng lặp chạy tối đa 9 lượt (số lượng ô)
Hiển thị bàn cờ: O(1)
Nhập vị trí từ người chơi: O(1)
Kiểm tra hợp lệ và cập nhật bàn cờ: O(1)
Kiểm tra chiến thắng: O(1)
Chuyển lượt chơi: O(1)
Độ phức tạp: O(1), vì số lượng lượt tối đa là hằng số
Tổng cộng, độ phức tạp của chương trình trò chơi Tic Tac Toe được thể hiệnbằng O(1), vì toàn bộ chương trình chạy trong một lượng lượt cố định (tối đa 9lượt) và không phụ thuộc vào kích thước của dữ liệu đầu vào
3 Puzzle (Puzzle.cpp)
a Mô tả
sử dụng OpenMP để giải bài toán 8-Puzzle Bài toán 8-Puzzle là một trò chơi trên bảng 3x3 với 8 ô số và một ô trống Mục tiêu là di chuyển các số để sắp xếp chúng thành một trạng thái cụ thể
b Giải thích code và cách giải
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#define N 3
void printPuzzle(int puzzle[N][N]) {
#pragma omp critical
Trang 22// Hoán d?i v? trí c?a s? 0 v?i s? bên c?nh nó
if (direction == 0 && i > 0) { // Di chuy?n lên trên int temp = puzzle[i][j];
puzzle[i][j] = puzzle[i - 1][j];
puzzle[i - 1][j] = temp;
Trang 23} else if (direction == 1 && i < N - 1) { // Di chuy?n xu?ng du?i int temp = puzzle[i][j];
puzzle[i][j] = puzzle[i + 1][j];
puzzle[i + 1][j] = temp;
} else if (direction == 2 && j > 0) { // Di chuy?n sang trái
int temp = puzzle[i][j];
#pragma omp parallel for ordered schedule(static, 1)
for (int thread_id = 0; thread_id < 4; thread_id++) {
// T?o m?t b?n sao c?a câu d? cho m?i thread