Tải bản đầy đủ (.doc) (17 trang)

Đồ Án Chương trình giải được ô số sudoku có kích thước 9x9 full five code

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (327.63 KB, 17 trang )

Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
Mục Lục

I.Giới thiệu : 2
1. Lịch sử ra đời: 2
2. Luật chơi: 3
II.Cấu trúc dữ liệu: 5
III.Thuật toán: 5
1. Thuật toán cơ bản: 5
2. Thuật toán cụ thể : 7
IV.Chương trình: 9
V. Kết quả: 16
VI. NHẬN XÉT: 17
Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 1
Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
I.Giới thiệu :

Sodoku hay còn gọi là Sudoku là một trò chơi trí tuệ nổi tiếng trên thế giới
được nhiều người biết đến. Ta hãy cùng tìm hiểu về lịch sử của ô số này nhé ^^.
1. Lịch sử ra đời:
Sudoku có lịch sử xa xưa từ hàng ngàn năm. Nó từng đi qua các nền văn hóa
cổ, và có lẽ nó bắt nguồn từ Trung Hoa, theo như một
tài liệu của Ả rập vào thế kỷ thứ 9. Năm 990, một danh
sách những “Ô số kỳ ảo” đã xuất hiện và tỏ ra không
khác mấy so với bản Sudoku xuất hiện trong Từ Điển
Bách Khoa Ikhwan al-salfa cùa các học giả người Ả
Rập. Trong từ điển này, họ gọi nó là wafq.
Abraham Ben ibn Ezra - một nhà triết học kiêm
chiêm tinh học người Hispanic (Tây Ban Nha - Bồ
Đào Nha) gốc Do thái - bắt đầu quảng bá khối vuông buduh ở châu Âu. Ông đi


khắp Tây Ban Nha, Ý và các nước khác ở châu Âu để giới thiệu với công chúng
về “những ô số kỳ ảo”.
Sudoku có thêm một bước tiến hóa mới vào năm 1776 khi một nhà toán học
kiêm vật lý học người Thuỵ Sĩ tên Leonhard Euler bắt
đầu nghiên cứu và phát triển các luật chơi mà ngày nay ta
gọi là luật chơi Sudoku. Năm 1901, một nhà toán học
người Pháp tiếp tục công trình này và năm 1959, hai
người Mỹ tên là Bose và Shrikhande nối gót theo ông ta.
Đi xuyên qua một cuộc hành trình dài lâu và kiên trì,
Sudoku lần đầu tiên được xuất bản vào cuối thập niên
1970 trong một tờ tạp chí ở New York. Tờ tạp chí này đã
giới thiệu về các ô số kỳ ảo và khuôn nó lại trong một
lưới 9x9, tạo thành từ các khối 3x3. Và như thế, Sudoku
đã ra đời.
Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 2
Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
Năm 1986, trong một chuyến đi Mỹ, một nhà xuất bản Nhật Bản, Nikoli, đã
khám phá ra các ô số. Họ đặt tên cho nó là SuDoku (Su là
số, Doku là đơn độc), và làm cho nó nhanh chóng trở
thành một trò chơi phổ biến ở Nhật Bản.
Sau hơn 20 năm, một thẩm phán người Hồng Kông
gốc New Zealand tên là Wayne Gould tình cờ phát hiện
một cuốn sudoku trong một hiệu sách Nhật Bản. Ông đâm
nghiền trò chơi số cổ xưa này. Năm 2004, niềm đam mê
Sudoku đã đưa Wayne Gould đến với London (Anh).
Nhân một chuyến thăm ngẫu nhiên báo The Times, Gould
đã thuyết phục tổng biên tập của báo này cho đăng Sudoku
bên cạnh các ô chữ. Độc giả lập tức bị cuốn hút và yêu cầu
đăng thêm nữa. Chỉ trong vài tuần lễ, các tờ báo trên khắp

nước Anh đã thi nhau đăng Sudoku. Từ đó, Sudoku bắt đầu lan rộng sang Mỹ,
Canada, Úc, Pháp, Nam Phi và nhiều quốc gia khác.

2. Luật chơi:
Luật chơi Sudoku cực kỳ đơn giản, nhưng đáp án đôi khi lại cực kỳ khó giải.
Do không cần dùng đến kiến thức số học hay tính toán, Sudoku thích ứng cho mọi
người. Vì vậy trẻ em cũng có cơ hội giải được Sudoku thành công như người lớn.
Trên thực tế, ở một số nước châu Âu, các em nhỏ đã chiến thắng người lớn trong
các cuộc thi đấu Sudoku. Luật chơi như sau:
Điền vào những ô trống những con số thích hợp, theo quy luật đơn giản sau:
- Các ô ở mỗi hàng (ngang) phải có đủ các số từ 1 đến 9, không cần theo thứ tự.
- Các ô ở mỗi cột (dọc) phải có đủ các số từ 1 đến 9, không cần theo thứ tự.
- Mỗi miền 3x3, được viền đậm, phải có đủ các số từ 1 đến 9.
Trò chơi bắt đầu với một lưới Sudoku, trong đó một số ô đã cho sẵn các con số
đúng. Bạn phải suy luận để tìm ra những con số trong các ô trống còn lại.
Các đề sudoku mức dễ thường bắt đầu với nhiều con số đã được điền sẵn, do đó
bạn sẽ dễ tìm ra đáp án hơn. Càng tìm ra nhiều con số, bạn sẽ càng dễ tìm ra các
con số khác.
Ngoài khuôn dạng chuẩn có kích thước 9x9 ô, chia làm 3x3 vùng, còn có rất
nhiều biến thể khác. Một số biến thể phổ biến như:
- Kích thước 4x4 ô chia làm 2x2 vùng
- Kích thước 6x6 ô chia làm 2x3 vùng
Biến thể với kích thước lớn cũng khá phổ biến:
- Kích thước 16x16 ô (Monster SuDoku)
- Kích thước 12x12 ô chia làm 4x3 vùng (Dodeka Sudoku)
- Kích thước 25x25 ô (Giant Sudoku)
- Biến thể có kích thước lớn nhất được phổ biến là 100x100 ô.
Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 3
Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc

VD:
Kết quả:

Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 4
Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
II.Cấu trúc dữ liệu :
Trong bài nãy ta chỉ xét đến ô sudoku có kích thước 9x9.
Ta có thể biểu diễn ô số sudoku bằng mảng 2 chiều.
Và sử dụng kiểu bản ghi cell gồm trường value để chứa giá trị của một ô và
trường set là tập hợp các giá trị đề cử cho ô đó.
typedef struct cell
{
int value;
int set[10];
};
typedef cell sudoku[10][10];
sudoku a;
III.Thuật toán :
Có nhiều giải thuật được đưa ra để giải ô số sudoku nhưng ở đây ta sử dụng
giải thuật đệ quy quay lui.
1. Thuật toán cơ bản:

• Kỹ thuật quay lui (backtracking) như tên gọi của nó, là một quá trình tìm
kiếm mà trong quá trình tìm kiếm, nếu ta gặp một hướng lựa chọn không thỏa
mãn, ta quay lui về điểm lựa chọn nơi có các hướng khác và thử hướng lựa
chọn tiếp theo. Quá trình tìm kiếm thất bại khi không còn điểm lựa chọn nào
nữa.
Thuật toán quay lui có thể được mô tả bằng đoạn giả mã sau:
{Thủ tục này thử cho xi nhận lần lượt các giá trị mà nó có thể nhận}

procedure Try(i: Integer);
begin
for (mọi giá trị có thể gán cho xi) do
begin
<Thử cho xi := V>;
if (xi là phần tử cuối cùng trong cấu hình) then
<Thông báo cấu hình tìm được>
else
begin
<Ghi nhận việc cho xi nhận giá trị V (Nếu cần)>;
Try(i + 1); {Gọi đệ qui để chọn tiếp xi + 1}
Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 5
Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
<Nếu cần, bỏ ghi nhận việc thử xi := V, để thử giá trị khác>;
end;
end;
end;
Ta có thể trình bày quá trình tìm kiếm lời giải quả thuật toán quay lui bằng
cây sau:

• Đệ quy (recursion) là một thuật toán được xây dựng dựa trên chính nó.
Một chương trình con đệ qui căn bản gồm hai phần.
- Phần cơ sở: chứa các tác động của hàm hoặc thủ tục với một số giá trị cụ thể ban
đầu của tham số.
- Phần đệ qui: định nghĩa tác động cần được thực hiện cho giá trị hiện thời của các
tham số bằng các tác động đã được định nghĩa trước đây với kích thước tham số
nhỏ hơn.
Vd: Tính giai thừa bằng đệ quy
int giaithua (int n)

{ if(n==0||n=1) return(1);
else return(n*giaithua(n-1));
}
Trong ví dụ trên, quy trình thực hiện như sau:
- Khi có lệnh gọi hàm: chẳng hạn giaithua(3) thì máy sẽ ghi nhớ là:
giaithua(3) = 3* giaithua(2) và kế tiếp là đi tính giai thừa của 2 thì máy sẽ nhớ
là:
giaithua(2) = 2* giaithua(1) và theo định nghĩa của hàm thì giaithua(1) = 1 .
Sau đó, máy sẽ quay ngược lại tính giai thừa của 2 và kế tiếp là giai thừa của 3 .
Cuối cùng, ta được kết quả là : giaithua(3) = 6
• Thuật toán quay lui tổng quát: đệ quy
Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 6
Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
Thuật toán được mô tả bằng đoạn giả mã sau:
quaylui_dequy(k)
begin
if (s=(s
1
, s
2
, …, s
k
) là giải pháp) then xuly(s)
else
for j from 1 to |A
k
| do //thử tất cả các giá trị có thể
s
k

= a
k
j
//A
k
= {a
k
1
, a
k
2
,…}
if (( s
1
, s
2
, …, s
k
) là có triển vọng) then
quaylui_dequy(k+1) //xây dựng thành phần tiếp theo
endif
endfor
endif
end
2. Thuật toán cụ thể :
- Trước khi áp dụng giải thuật đệ quy quay lui để giải ô sudoku,ở mỗi ô, ta lọc
trước các giá trị mà ô đó có thể nhận.
Thuật toán cụ thể như sau: duyệt lần lượt từng ô xem thử trong cùng hàng,
cột, block đã tồn tại giá trị value nào chưa, nếu có thì loại giá trị đó ra khỏi tập các
giá trị đề cử. Chẳng hạn, trong ví dụ trên: ở ô [1][1] ta có thể loại ra các giá trị 1,

2, 4, 5, 6, 8, 9. Như vây, sau khi lọc, tập giá trị mà ô đó có thể nhận chỉ gồm
{3,7} . Cứ tiếp tục lọc cho đến ô cuối cùng (ô [9][9]) . Mục đích của việc này là
nhằm giảm bớt số lần quay lui. Sau đây là các hàm lọc theo hàng, cột, và block.
********************************************
void filter_row(int i, int vl, int num)
{
int j;
for (j=1;j<=n;j++)
a[i][j].set[vl]=num;
}
********************************************
void filter_col(int j, int vl, int num)
{
int i;
for (i=1;i<=n;i++) a[i][j].set[vl]=num;
}
********************************************
void filter_bl(int i, int j, int vl, int num)
{
Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 7
Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
int row=get_bl(i);
int col=get_bl(j);
for (int t=row;t<=row+2;t++)
for (int k=col;k<=col+2;k++)
a[t][k].set[vl]=num;
}
********************************************
- Sau khi lọc xong, ta dùng thuật toán đệ quy quay lui dựa trên phương

pháp thử và sai. Đầu tiên, ta xác định ô đó thuộc hàng i, cột j theo công thức:
i=(index-1)/9+1
j=(index-1)%9
Nếu a[i][j] =0 tức là ô đó chưa có lời giải thì bắt đầu duyệt qua các giá trị đề
cử và xem thử t có tồn tại trên cùng hàng, cột hay block chưa ,nếu chưa thì
điền t vào ô đó. Nếu đã xét đủ 81 ô thì in ra kết quả, còn không đủ thì xét đến
ô tiếp theo. Nếu không đặt giá trị đó vào ô đó được thì quay lui.
********************************************
void trycell (int index)
{
int i,j,t;
i=(index-1)/9+1;
j=(index-1)%9+1;
if (index>tt) tt=index; //dieu kien dung
if (!a[i][j].value)
{
for (t=1;t<=9;t++)
if ((!a[i][j].set[t])&&(!valueExisted(t,i,j)))
{
a[i][j].value=t; //thu sai
if (index<81) trycell(index+1); // neu index=81 thi in ket qua
else
{ output();
exit(1);
}
if (!a[i][j].set[0]) a[i][j].value=0; //quay lui
}
} else trycell(index +1);
}
********************************************

Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 8
Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
IV.Chương trình :
#include<conio.h>
#include<stdio.h>
#include<stdlib.h>
const int n=9;
typedef struct cell
{
int value;
int set[10];
};
typedef cell sudoku[10][10];
sudoku a;
int tt=0;
void create();
void output();
void filter_row(int i,int vl,int num);
void filter_col(int j,int vl,int num);
int get_bl(int i);
void filter_bl(int i,int j,int vl,int num);
int filtercell(int h,int c,int vl,int num);
void filter();
int valueExisted(int vl,int h,int c);
int errordata(sudoku a);
void trycell(int index);
void DrawRectang(int left,int top,int width,int height,int color);
void write_string(char *str,int x,int y,int color);
void introduce();

/*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*/
//doc du lieu tu file input.txt
void create()
{
int i,j,t;
FILE *f;
f=fopen("input.txt","r");
if (f==NULL)
{
printf("File khong ton tai ! Kiem tra va dat file intput.txt vao cung thu muc
chua file sudoku.exe!");
Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 9
Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
getch();
exit(1);
}
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
{
fscanf(f,"%d",&t);
a[i][j].value=t;
}
fclose(f);
}
/*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*/
//xuat ra o so sudoku neu giai duoc
void output()
{
int i,j;

printf("\n");
for (i=1;i<=n;i++)
{
if (i%3==1) printf("\n");
for (j=1;j<=n;j++)
{
if (j%3==1) printf(" ");
printf("%3d",a[i][j].value);
}
printf("\n");
}
getch();
}
/*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*/
//ham loc hang
void filter_row(int i, int vl, int num)
{
int j;
for (j=1;j<=n;j++)
a[i][j].set[vl]=num;
}
/*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*/
//ham loc cot
void filter_col(int j, int vl, int num)
{
int i;
Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 10
Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
for (i=1;i<=n;i++)

a[i][j].set[vl]=num;
}
/*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*/
//ham xac dinh block
int get_bl(int i)
{
switch (i)
{
case 1:
case 2:
case 3: i=1; break;
case 4:
case 5:
case 6: i=4; break;
case 7:
case 8:
case 9: i=7; break;
}
return(i);
}
/*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*/
//ham loc block
void filter_bl(int i, int j, int vl, int num)
{
int row=get_bl(i);
int col=get_bl(j);
for (int t=row;t<=row+2;t++)
for (int k=col;k<=col+2;k++)
a[t][k].set[vl]=num;
}

/*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*/
//ham loc hang, cot, block tai 1 o
void filtercell(int h, int c, int vl, int num)
{
filter_row(h,vl,num);
filter_col(c,vl,num);
filter_bl(h,c,vl,num);
}
/*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*/
//ham loc toan bo o so sudoku
void filter()
Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 11
Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
{
int i,j;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
if(a[i][j].value)
{
a[i][j].set[0]=1; //danh dau gia tri ban dau cua du lieu vao
filtercell(i,j,a[i][j].value,1);
}

}
/*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*/
//ham kiem tra mot gia tri nao do da ton tai tren hang, cot, block dang xet
int valueExisted(int vl,int h,int c)
{
int i,j;

int ok=0;
for (j=1;j<=n;j++)
if ((a[h][j].value==vl)&&(j!=c))
{
ok=1; break;
}
if (!ok)
for (i=1;i<=n;i++)
if ((a[i][c].value==vl)&&(i!=h))
{
ok=1; break;
}
if (!ok)
{
int row=get_bl(h);
int col=get_bl(c);
for (int tt=row;tt<=row+2;tt++)
for (int k=col;k<=col+2;k++)
if ((a[tt][k].value==vl)&&(tt!=h)&&(k!=c))
{
ok=1; break;
}
return ok;
}
}
/*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*/
Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 12
Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
//ham kiem tra du lieu vao

int errordata(sudoku a)
{
int i,j,ok=0;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
if (a[i][j].value)
if (valueExisted(a[i][j].value,i,j))
{
ok=1; break;
}
return ok;
}
/*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*/
//ham thu sai quay lui dien o sudoku
void trycell(int index)
{
int i,j,t;
i=(index-1)/9+1;
j=(index-1)%9+1;
if (index>tt) tt=index; //dieu kien dung
if (!a[i][j].value)
{
for (t=1;t<=9;t++)
if ((!a[i][j].set[t])&&(!valueExisted(t,i,j)))
{
a[i][j].value=t; //thu sai
if (index<81) trycell(index+1); //neu index = 81 thi in ket qua
else
{
printf("\n Ket qua: ");

output();
exit(1);
}
if (!a[i][j].set[0]) a[i][j].value=0; //quay lui
}
} else trycell(index +1);
}
/*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*/
void DrawRectang(int left,int top,int width,int height,int color)
{
int i;
Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 13
Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
textcolor(color);
gotoxy(left, top);
putch(201);
gotoxy(left, top+height+1);
putch(200);
gotoxy(left+width+1, top);
putch(187);
gotoxy(left+width+1, top+height+1);
putch(188);
for (i=1;i <=width; i++)
{
gotoxy(left+i, top);
putch(205);
gotoxy(left+i, top+height+1);
putch(205);
}

for ( i=1; i<=height ; i++)
{
gotoxy( left, top+i);
putch(186);
gotoxy( left+width+1, top+i);
putch(186);
}
return ;
}
/*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*/
void write_string(char *str,int x,int y,int color)
{
textcolor(color);
gotoxy(x, y);
cprintf(str);
return;
}
/*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*/
void introduce()
{
clrscr();
DrawRectang ( 20, 14 , 40 , 7, 2);
write_string(" Truong Dai Hoc Bach Khoa Da Nang ", 23, 15 , 11);
write_string(" Khoa Cong Nghe Thong Tin ", 23, 16 , 11);
write_string(" GVHD : LE QUY LOC ",23, 17 ,11);
write_string(" NHOM : 11",23, 18 ,11);
Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 14
Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
write_string(" LOP : 06T4",23, 19 ,11);

write_string(" HO TEN SV: NGUYEN HOANG NGUYEN ",23, 20 ,11);
write_string(" DANG THI QUYNH NHU ",23, 21 ,11);
textcolor(7);
gotoxy(10,24);
cprintf("\n Please press enter to see the result ");
return;
}
/*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*==*/
//chuong trinh chinh
int main(void)
{
introduce();
textcolor(2);
textbackground(0x20);
int t; create();
output();
if (errordata(a))
{
printf("Loi du lieu! Xin kiem tra lai input file!");
getch();
exit(1);
}
printf("\n");
filter();
trycell(1);
if (tt<81) printf("\nO sudoku nay khong co loi giai!");
getch();
}

Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 15

Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
V. Kết quả:
Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 16
Nhóm 11
Đồ án môn học: Cấu trúc dữ liệu GVHD: Lê Quý Lộc
VI. NHẬN XÉT:

Chương trình giải được ô số sudoku có kích thước 9x9 có mức độ từ dễ đến
khó. Hạn chế của chương trình là nếu dữ liệu đầu vào quá ít ( mức độ impossible )
thì chương trình có thể không đưa ra được kết quả. Bài toán sudoku là bài toán
phức tạp nên nhóm chỉ thao tác với chế độ văn bản. Đây là đồ án đầu tiên nên khó
tránh khỏi sai sót, rất mong sự giúp đỡ của thầy và em xin cảm ơn thầy đã hướng
dẫn chúng em.

SV thực hiện: Nguyễn Hoàng Nguyện
Đặng Thị Quỳnh Như
Lớp : 06T4
Nhóm : 11
GVHD : Lê Quý Lộc
Nguyễn Hoàng Nguyện – Đặng Thị Quỳnh Như Page 17
Nhóm 11

×