You are on page 1of 11

- Đầu tiên, tạo bảng sudoku bằng các lệnh trên matlabo một figure

- if size(B,2) == 9 % trả về số lượng cột


- [SM,SN] = meshgrid(1:9); % make i,j entries
- B = [SN(:),SM(:),B(:)]; % i,j,k rows
- Kiểm tra xem số
hàng của SM ví dụ lấy theo hàng 1 2 3 của cột 1 thì các giá trị là 111 , cột

có phải ma trận 9x9 không


% Convert to 81-by-3
[SM,SN] = meshgrid(1:9) % make i,j entries
B = [SN(:),SM(:),B(:)] % i,j,k rows
% Now delete

if size(B,2) ~= 3 || length(size(B)) > 2


error('The input matrix must be N-by-3 or 9-by-9')
end
 size(B,2) ~= 3: Kiểm tra xem số cột của ma trận B có phải là 3 không. Nếu B không
có đúng 3 cột, điều kiện này trả về true.
 length(size(B)) > 2 : Kiểm tra xem B có nhiều hơn hai chiều không (tức là kiểm tra
xem B có phải là ma trận không). Một ma trận hợp lệ chỉ nên có hai chiều.
 Nếu một trong hai điều kiện trên đúng, hàm error sẽ được gọi với thông điệp lỗi,
thông báo rằng ma trận đầu vào phải là N-by-3 hoặc 9-by-9. Điều này đảm bảo
rằng đầu vào phải có kích thước hợp lệ trước khi tiến hành các bước xử lý tiếp
theo trong hàm.

Đầu vào của ma trận phải có dạng Nx3 hoặc 9x9

if sum([any(B ~= round(B)),any(B < 1),any(B > 9)]) % enforces entries 1-9


error('Entries must be integers from 1 to 9')
end
 B ~= round(B) : Kiểm tra xem tất cả các phần tử trong B có phải là số nguyên
không. round(B) làm tròn tất cả các phần tử của B đến số nguyên gần nhất, và
nếu B không bằng phiên bản làm tròn của nó, điều này chỉ ra rằng có các phần
tử không phải là số nguyên.
 B < 1 và B > 9: Kiểm tra xem có bất kỳ phần tử nào của B có giá trị nhỏ hơn 1 hoặc
lớn hơn 9 không. Trong Sudoku, chỉ các số từ 1 đến 9 là hợp lệ.
 any(...): Hàm any trả về true nếu có bất kỳ phần tử nào trong mảng thoả mãn điều
kiện kiểm tra.
 sum(...): Tính tổng số các điều kiện vi phạm. Nếu tổng này lớn hơn 0, điều đó có
nghĩa là có ít nhất một lỗi được phát hiện.
 error(...): Nếu bất kỳ điều kiện kiểm tra nào cho giá trị không đạt, hàm error được
gọi để dừng thực thi chương trình và hiển thị thông điệp lỗi, chỉ ra rằng tất cả các
mục phải là số nguyên từ 1 đến 9.

Các giá trị phải là số nguyên từ 1-9

N = 9^3; % number of independent variables in x, a 9-by-9-by-9 array


M = 4*9^2; % number of constraints, see the construction of Aeq
Aeq = zeros(M,N); % allocate equality constraint matrix Aeq*x = beq
beq = ones(M,1); % allocate constant vector beq
f = (1:N)'; % the objective can be anything, but having nonconstant f can speed the
solver
lb = zeros(9,9,9); % an initial zero array
ub = lb+1; % upper bound array to give binary variables

N = 9^3 bắt nguồn từ số lượng biến tổng thể tương ứng với số lượng các ô có thể trong
sudoku(9 ô mỗi hàng) nhân với số lượng giá trị có thể cho các ô là 1-9 nhân với 9
hàng
M = 4*9^2 (tổng số ràng buộc cần thiết) : Có 9 hàng và mỗi hàng chứa 1 số từ 1-9 .
điều này tạo ra 9 ràg buộc cho mỗi hàng , có tổng cộng 9 hàng nên có 81 ràng buộc.
Tương tự mỗi cột cũng có 9 ràng buộc , có 9 cột nên có 81 ràng buộc . Bảng chia ra
thành 9 lưới 3x3 và mỗi lưới cũng cần chứa số từ 1-9 1 lần => tổng ràng buộc là 9
lưới nhân 9 số = 81 ràng buộc, mỗi ô trên bảng đều chứa 1 số 1-9 nên có 81 ô nên có
81 ràng buộc

Aeq = zeros(M,N) khởi tạo ma trận các ràng buộc , lý do : dùng để định nghĩa các ràng
buộc đẳng thức của bài toán,nơi mỗi hàng đại diện cho một ràng buộc cụ thể, ví dụ 1
hàng phải đáp ứng cho 1 số xuất hiện đúng 1 lần trong hàng , cột , lưới
Aeq*x = beq là một ma trận giốngg như đại số tuyến tính

Aeq và beq : Ma trận và vecto cho các ràng buộc,


F : hàm mục tiêu , k cần thiết vi sudoku tìm lời giải khả thi chứ k cần tối uuw
 (1:N): Là một biểu thức trong MATLAB tạo ra một vector hàng chứa các số từ 1
đến N. Trong trường hợp này, nó tạo ra một vector từ 1 đến 729.
 (1:N)': Dấu phẩy đơn ( ') là toán tử chuyển vị trong MATLAB. Nó chuyển đổi
vector hàng thành vector cột. Vậy f sẽ là một vector cột từ 1 đến 729.
Lb và ub là giới hạn dưới và trên cho các biến , đặt thành 0 và 1 đẻ chỉ rõ các biến
là nhị phân(có mặt hay không có mặt) 9x9x9 vì tổng thể có 729 biến khả năng

counter = 1;
for j = 1:9 % one in each row
for k = 1:9
Astuff = lb; % clear Astuff
Astuff(1:end,j,k) = 1; % one row in Aeq*x = beq
Aeq(counter,:) = Astuff(:)'; % put Astuff in a row of Aeq
counter = counter + 1;
end
end
...

- DÙng để tạo ra các ràng buộc cho mỗi hàng của sudoku đảm bảo rằng các ôs từ 1-
9 chỉ xuất hiện 1 lần trong mỗi hàng
-
- Counter được sử dụng để theo dõi chỉ số của hàng hiện tại trong Aeq
Vòng lặp ngoài chạy từ 1-9 , mỗi lần lặp đại diện cho 1 cột
Vòng lặp trong chạy từ 1-9, mỗi lần lặp đại diện cho 1 số từ 1-9 . Mục tiêu là
thiết lập ràng buộc cho mỗi số ở trong cột
- Ma trận Astuff bằng giới hạn dưới , mảng 9x9x9 (3 chiều) . Mục đích của việc
này là để làm sạch hoặc thiết lập lại Astuff trước mỗi lần lặp để chuẩn bị cho
ràng buộc mới .
- Đặt tất cả các giá trị cột j và chiều sâu k = 1. Điều này có nghĩa là trong
bảng sudoku , xuất hiện 1 lần ở cột j và áp dụng cho tất cả các hàng
-
o Astuff = lb; làm sạch Astuff về trạng thái ban đầu (tức là toàn bộ các giá trị
bằng 0).
o Astuff(1:end,j,k) = 1; đặt tất cả các phần tử trong cột j và ở "chiều sâu" k của
Astuff thành 1. Nghĩa là trong bảng Sudoku, cho dù bạn đang ở hàng nào,
số k phải xuất hiện ít nhất một lần trong cột j.
- Chuyển đổi và lưu ràng buộc:
o Astuff(:)' làm phẳng mảng 3D Astuff thành một vector hàng.
o Aeq(counter,:) = Astuff(:)'; gán vector này vào hàng thứ counter của Aeq, từ đó
lưu trữ ràng buộc mà chúng ta vừa xây dựng.
- Tăng counter: Sau khi mỗi ràng buộc được tạo và lưu, counter tăng lên 1 để chuẩn
bị cho ràng buộc tiếp theo.
- Tương tự thế làm với ràng buộc của các cột

for U = 0:3:6 % one in each square


for V = 0:3:6
for k = 1:9
Astuff = lb;
Astuff(U+(1:3),V+(1:3),k) = 1;
Aeq(counter,:) = Astuff(:)';
counter = counter + 1;
end
end
end
Đoạn code này là một phần của quá trình xây dựng ma trận ràng buộc Aeq cho bài toán
Sudoku, cụ thể là để đảm bảo rằng mỗi số từ 1 đến 9 xuất hiện đúng một lần trong mỗi khối
3x3 của bảng Sudoku. Cấu trúc vòng lặp và các lệnh được sử dụng như sau:

Đoạn code này là một phần của quá trình xây dựng ma trận ràng buộc Aeq cho bài toán
Sudoku, cụ thể là để đảm bảo rằng mỗi số từ 1 đến 9 xuất hiện đúng một lần trong mỗi
khối 3x3 của bảng Sudoku. Cấu trúc vòng lặp và các lệnh được sử dụng như sau:

Vòng lặp ngoài cùng: for U = 0:3:6 % one in each square

 Vòng lặp này lặp qua các hàng của các ô 3x3. Giá trị U bắt đầu từ 0, tăng theo
bước là 3 và kết thúc ở 6, đại diện cho các hàng đầu tiên của mỗi khối 3x3 (có ba
khối 3x3 theo chiều dọc).

Vòng lặp thứ hai: for V = 0:3:6


 Vòng lặp này lặp qua các cột của các ô 3x3. Giá trị V bắt đầu từ 0, tăng theo bước
là 3 và kết thúc ở 6, đại diện cho các cột đầu tiên của mỗi khối 3x3 (có ba khối
3x3 theo chiều ngang).

Vòng lặp bên trong cùng: for k = 1:9

 Vòng lặp này lặp qua các số từ 1 đến 9. Mỗi số k cần được đảm bảo xuất hiện
đúng một lần trong mỗi khối 3x3.

Lệnh Astuff = lb;

 Lệnh này thiết lập Astuff bằng giá trị của lb (là ma trận khởi tạo giới hạn dưới, ban
đầu là toàn bộ các số 0). Astuff sẽ được sử dụng để xây dựng một ràng buộc cụ
thể.

Lệnh Astuff(U+(1:3),V+(1:3),k) = 1;

 Lệnh này đặt tất cả các phần tử trong một khối 3x3 cụ thể thành 1 cho số k.
U+(1:3) và V+(1:3) tính toán các chỉ số hàng và cột thực tế trong khối 3x3. Ví dụ,
nếu U = 0 và V = 0, thì khối 3x3 đầu tiên ở góc trên cùng bên trái của bảng Sudoku
sẽ được lựa chọn.

Lệnh Aeq(counter,:) = Astuff(:)';

 Lệnh này chuyển Astuff thành một vector hàng (bằng cách sử dụng (:)' để làm
phẳng mảng) và gán nó vào hàng thứ counter của ma trận Aeq. Ma trận Aeq sử
dụng các hàng này để biểu diễn ràng buộc trong bài toán ILP, đảm bảo rằng mỗi
số từ 1 đến 9 xuất hiện đúng một lần trong mỗi khối 3x3.

Lệnh counter = counter + 1;

 Lệnh này tăng biến đếm counter lên 1 sau mỗi lần lặp, để đảm bảo rằng hàng tiếp
theo của Aeq sẽ được gán cho ràng buộc tiếp theo trong quá trình xây dựng ma
trận.
for i = 1:9 % one in each depth
for j = 1:9
Astuff = lb;
Astuff(i,j,1:end) = 1;
Aeq(counter,:) = Astuff(:)';
counter = counter + 1;
end
end
1. Vòng lặp ngoài: for i = 1:9 % one in each depth
 Đây là vòng lặp qua mỗi hàng i của bảng Sudoku. Từ "depth" ở đây có thể gây nhầm lẫn,
nhưng trong ngữ cảnh này, nó chỉ đơn giản là đang lặp qua mỗi hàng của bảng.
2. Vòng lặp trong: for j = 1:9
 Vòng lặp này chạy qua mỗi cột j của bảng. Kết hợp với vòng lặp hàng, chúng ta đang xét
đến từng ô (i, j) trên bảng Sudoku.
3. Khởi tạo Astuff: Astuff = lb;
 Astuff được thiết lập lại thành lb mỗi khi bắt đầu một lần lặp mới. lb ban đầu là một
mảng ba chiều 9x9x9 với tất cả các phần tử là 0, và Astuff sử dụng cấu trúc này để xây
dựng ràng buộc mới.
4. Thiết lập ràng buộc: Astuff(i,j,1:end) = 1;
 Dòng này đặt tất cả các phần tử trong chiều thứ ba (tức là cho tất cả các số từ 1 đến 9)
của ô được chỉ định bởi hàng i và cột j thành 1. Điều này tạo ra một ràng buộc trong ILP
biểu thị rằng chỉ một số duy nhất (từ 1 đến 9) có thể được gán cho ô đó. Nói cách khác,
trong mỗi ô (i, j) của bảng Sudoku, chỉ có thể chọn một giá trị duy nhất.
5. Lưu ràng buộc vào Aeq: Aeq(counter,:) = Astuff(:)';
 Astuff(:)' làm phẳng mảng ba chiều Astuff thành một vector hàng. Sau đó, vector này
được gán vào hàng hiện tại của ma trận Aeq, được xác định bởi biến counter. Ma trận
Aeq sử dụng các hàng này để lưu trữ các ràng buộc của bài toán ILP.
6. Cập nhật counter: counter = counter + 1;
 Sau khi một ràng buộc được thêm vào Aeq, biến đếm counter được tăng lên 1 để ràng
buộc tiếp theo có thể được lưu vào hàng tiếp theo của Aeq.

for i = 1:size(B,1)
lb(B(i,1),B(i,2),B(i,3)) = 1;
end

Câu lệnh for i = 1:size(B,1) trong MATLAB, kết hợp với các lệnh bên trong nó, là một phần
của quá trình giải Sudoku bằng cách sử dụng lập trình tuyến tính nguyên (Integer Linear
Programming - ILP). Đây là cách thiết lập các giới hạn (constraints) trong mảng ba chiều
lb dựa trên các gợi ý hoặc số đã cho từ bảng Sudoku. Dưới đây là giải thích chi tiết về ý
nghĩa và chức năng của đoạn code này:

Giải thích Câu Lệnh

 for i = 1:size(B,1) : Đây là một vòng lặp for chạy từ 1 đến số hàng của ma trận B. Ma
trận B được giả định là chứa các gợi ý của bài toán Sudoku, với mỗi hàng của B
chứa ba giá trị: chỉ số hàng ( B(i,1)), chỉ số cột ( B(i,2)), và số cụ thể ( B(i,3)) cần điền
vào bảng Sudoku. size(B,1) trả về số lượng hàng trong ma trận B, tức là số gợi ý
đã cho.
 lb(B(i,1),B(i,2),B(i,3)) = 1; : Đây là câu lệnh thực hiện việc cập nhật mảng ba chiều lb,
mà thường được khởi tạo với toàn bộ giá trị là 0. Mỗi phần tử của lb tại vị trí
(B(i,1), B(i,2), B(i,3)) được thiết lập thành 1. Nghĩa là:
 B(i,1): Chỉ số hàng trong bảng Sudoku.
 B(i,2): Chỉ số cột trong bảng Sudoku.
 B(i,3): Giá trị số tương ứng cần được đặt vào ô tại hàng B(i,1) và cột B(i,2).

Mục Đích Của Câu Lệnh

Mục đích chính của đoạn code này là đảm bảo rằng các số đã được cung cấp trước như
một phần của bài toán Sudoku được bảo toàn trong quá trình giải quyết bài toán sử
dụng ILP. Việc thiết lập lb(B(i,1),B(i,2),B(i,3)) = 1 bảo đảm rằng trong giải pháp cuối cùng, ô
tại vị trí đã chỉ định sẽ chứa số đã cho, làm cho nó cố định và không thay đổi. Điều này
giúp hạn chế không gian tìm kiếm của giải thuật ILP và định hướng giải thuật tới một lời
giải đúng đắn theo các gợi ý đã biết từ đầu.

intcon = 1:N;

[x,~,eflag] = intlinprog(f,intcon,[],[],Aeq,beq,lb,ub);
%% Convert the Solution to a Usable Form
% To go from the solution x to a Sudoku grid, simply add up the numbers at
% each $(i,j)$ entry, multiplied by the depth at which the numbers appear:

if eflag > 0% good solution


x = reshape(x,9,9,9); % change back to a 9-by-9-by-9 array
x = round(x); % clean up non-integer solutions
y = ones(size(x));
for k = 2:9
y(:,:,k) = k; % multiplier for each depth k
end

S = x.*y; % multiply each entry by its depth


S = sum(S,3); % S is 9-by-9 and holds the solved puzzle
else
S = [];
end
end

 intlinprog: Là hàm giải quyết bài toán lập trình tuyến tính nguyên trong
MATLAB.
 f: Vector chi phí, mỗi phần tử đại diện cho chi phí liên quan đến một biến cụ thể.
 intcon: Vector chỉ rõ các biến nào là biến nguyên.
 Aeq, beq: Ma trận ràng buộc bằng và vector giá trị tương ứng để xác định các
điều kiện bằng.
 lb, ub: Các giới hạn dưới và trên cho các biến (trong trường hợp này là 0 và 1,
tạo thành các biến nhị phân).
 x: Vector lời giải trả về từ hàm intlinprog, nếu có lời giải.
 eflag: Một flag trạng thái để chỉ ra liệu bài toán đã được giải quyết thành công
hay không (eflag > 0 nếu có lời giải hợp lệ).
 if eflag > 0: Kiểm tra xem bài toán có lời giải hợp lệ không.
 reshape(x,9,9,9): Chuyển đổi vector lời giải x thành một mảng 3D 9x9x9, phù
hợp với bảng Sudoku.
 round(x): Làm tròn các giá trị của x để loại bỏ các phần thập phân, chỉ cần thiết
nếu thuật toán trả về giá trị không chính xác do sai số tính toán.
 ones(size(x)): Tạo một mảng cùng kích thước với x với tất cả các giá trị là 1.
 for k = 2:9: Vòng lặp qua từng "tầng" thứ 2 đến 9 của y, thiết lập mỗi tầng với
giá trị của số tương ứng. Điều này tạo ra các bội số cho mỗi số trong bảng
Sudoku.
 *x.y: Nhân từng phần tử của x với bội số tương ứng của nó trong y. Điều này
chuyển từ biểu diễn nhị phân của lời giải (trong đó chỉ có một phần tử 1 cho mỗi
số trong mỗi ô) thành giá trị số thực tương ứng.
 sum(S,3): Tính tổng theo chiều thứ ba (tức là tổng các số trong từng ô), tạo ra
một ma trận 9x9 cuối cùng chứa lời giải Sudoku.
 Nếu không có lời giải hợp lệ ( eflag <= 0), S sẽ là một mảng rỗng, biểu thị không có
lời giải có thể.

Như vậy, đoạn code này chịu trách nhiệm không chỉ giải quyết bài toán Sudoku mà còn
chuyển đổi lời giải thành định dạng có thể sử dụng, kiểm tra xem lời giải có phù hợp
hay không, và cuối cùng là cung cấp lời giải dưới dạng bảng Sudoku 9x9.

a = [
5, 3, 0, 0, 7, 0, 0, 0, 0;
6, 0, 0, 1, 9, 5, 0, 0, 0;
0, 9, 8, 0, 0, 0, 0, 6, 0;
8, 0, 0, 0, 6, 0, 0, 0, 3;
4, 0, 0, 8, 0, 3, 0, 0, 1;
7, 0, 0, 0, 2, 0, 0, 0, 6;
0, 6, 0, 0, 0, 0, 2, 8, 0;
0, 0, 0, 4, 1, 9, 0, 0, 5;
0, 0, 0, 0, 8, 0, 0, 7, 9
];

clc;flag=0;
for i=1:9
for k=1:9
if a(i,k)>0
c=[i,k,a(i,k)]
flag=1;
break
end
end
if (flag==1)
break
end
end
for i=1:9
for k=1:9
if a(i,k)>0
b=[i,k,a(i,k)]
c=[b;c]
end
end
end

drawSudoku1(c)
type sudokuEngine
S=sudokuEngine(c)
drawSudoku1(S)

Ma trận A là ma trạn đề bài ban đầu , ma trận C là một ma trận Nx3 để cùng kích cỡ
với ma trận B trong drawsudoku1 gồm các hàng chứa 3 cột và các giá trị lần lượt của
nó trong hàng là (vị trí hàng, vị trí cột , giá trị) của ô trong ma trận A khi nó lớn
hơn 0 . đặt biến flag để dừng
1. Duyệt qua ma trận a để tìm ô chưa điền đầu tiên:
o Sử dụng hai vòng lặp for để duyệt qua từng phần tử của ma trận a.
o Nếu tìm thấy ô có giá trị khác 0, lưu lại tọa độ của ô đó (dòng và cột) vào biến c.
o Đặt cờ flag thành 1 để kết thúc việc duyệt.
2. Duyệt lại ma trận a để lấy tất cả các ô đã điền:
o Sử dụng hai vòng lặp for khác để duyệt qua từng phần tử của ma trận a.
o Nếu tìm thấy ô có giá trị khác 0, lưu lại tọa độ của ô đó và giá trị của nó vào biến b.
o Thêm tọa độ và giá trị của ô vào biến c.

You might also like