THUẬT TOÁN QUAY LUI (VÉT CẠN)
1. Mã đi tuần :
//Ham kiem tra kha nang di tiep
int KhaNang(int x, int y)//tra ve so quan ma co the dat,cua quan ma dang xet
{
int dem = 0;
int xGiaDinh, yGiaDinh;
for (int i = 0; i < 8; i++)//chay 8 vi tri
{
xGiaDinh = x + dx[i];
yGiaDinh = y + dy[i];
if (xGiaDinh >= 1 && xGiaDinh <= size && yGiaDinh >= 1 && yGiaDinh
<= size && matrix[xGiaDinh, yGiaDinh] == -1)//thuoc ban co,vi tri con trong
dem++;
}
return dem;
}
//b4 Ham ma di tuan
void MaDiTuan(int x, int y,int step)
{
int min = 8;//8 vi tri xung quanh con ma
int xTiepTheo = x, yTiepTheo = y;//vi tri tiep theo
for (int i = 0; i < 8; i++)
{
int xGiaDinh = x + dx[i];//xet vi tri cua con ma tiep theo,bang cach
lien doi no voi mang vi tri
int yGiaDinh = y + dy[i];
if (xGiaDinh >= 1 && xGiaDinh <= size && yGiaDinh >= 1 && yGiaDinh <=
size && matrix[xGiaDinh, yGiaDinh] == -1)//vi tri con trong ban co va chua co quan ma
nao dat vao
{
if (KhaNang(xGiaDinh, yGiaDinh) < min)//neu kha nang vi tri ma co
the dat be hon 8
{
min = KhaNang(xGiaDinh, yGiaDinh);//de lay ra so vi tri co the
dat quan ma tep theo
xTiepTheo = xGiaDinh;//luu vi tri cua quan ma dang xet
yTiepTheo = yGiaDinh;
}
}
}
if (xTiepTheo != x || yTiepTheo != y)//vi tri ko trung nhau_con co the di
{
step++;//buoc tang len
viTriX[step] = xTiepTheo;//vi tri thu "step" la vi tri cua quan ma nay
viTriY[step] = yTiepTheo;
matrix[xTiepTheo, yTiepTheo] = 1;//vi tri da dat quan ma moi thi danh
dau lai
MaDiTuan(xTiepTheo, yTiepTheo,step);
}
else
{
//het duong di
if (step < size * size)
coduongdi = false;
}
}
//cách khác
const int MAX = 8;
const int dong[] = {-1,-2,-2,-1, 1, 2, 2, 1};
const int cot[] = { -2, -1, 1, 2, 2, 1, -1, -2 };
int n;
int x, y;
int a[MAX][MAX];
int stt; //buoc nhay
int so_loi_giai = 0;
void Try(int x,int y,FILE *fin);
void XuatKQ(FILE *fin);
FILE *fin;
int main()
{
cout << "Nhap vao n:";
cin >> n;
//cout << "Nhap vao vi tri xuat phat:";
//cin >> x >> y;
fopen_s(&fin,"OUT.TXT","wt");
for (x = 0; x < n;++x)
for (y = 0; y < n; ++y)
{
a[x][y] = 1;
stt = 1;
Try(x, y,fin);
a[x][y] = 0;
}
if (so_loi_giai == 0)
cout << "Khong co loi giai"<<endl;
fclose(fin);
system("pause");
return 0;
}
void Try(int x, int y,FILE *fin)
{
if (stt >= n*n)
XuatKQ(fin);
else
{
for (int i = 0; i < 8; ++i)
{
int dongmoi = x + dong[i];
int cotmoi = y + cot[i];
if (0 <= dongmoi && dongmoi < n &&
0 <= cotmoi && cotmoi < n &&
a[dongmoi][cotmoi] == 0)
{
++stt;
a[dongmoi][cotmoi] = stt;
Try(dongmoi, cotmoi,fin);
a[dongmoi][cotmoi] = 0;
stt;
}
}
}
}
void XuatKQ(FILE *fin)
{
++so_loi_giai;
cout << "Loi giai thu :" << so_loi_giai << endl;
fprintf(fin,"Loi giai thu :%d",so_loi_giai);
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
printf("%3d",a[i][j]);
fprintf(fin,"%3d",a[i][j]);
}
cout << endl;
fprintf(fin,"\n");
}
cout << endl;
fprintf(fin,"\n");
cout << endl;
fprintf(fin,"\n");
}
2. Tám quân hậu :
int dong[8], cot[8], cheosac[15], cheohuyen[15], dem=0;
FILE *fon;
void print ()
{
int i;
printf("Cach %d:\n",dem+1);
fprintf(fon,"Cach %d:\n",dem+1);
for (i=0; i<8; i++)
{
printf("Buoc %d: Tren dong %3d dat quan Hau o cot %d\n",i+1,i, dong[i]);
fprintf(fon,"Buoc %d: Tren dong %3d dat quan Hau o cot %d\n",i+1,i,
dong[i]);
}
printf("\n");
fprintf(fon,"\n");
}
void thu(int i)
{
int j;
if (i<=7)
{
for (j=0; j<8; j++)
if (cot[j] == 1 && cheosac[i+j] ==1 && cheohuyen[i-j+7] == 1)
{
dong[i] = j; cot[j] = 0;
cheosac[i+j] = 0;
cheohuyen[i-j+7] = 0;
thu(i+1);
cot[j] = 1;
cheosac[i+j] = 1;
cheohuyen[i-j+7] = 1;
}
}
else
{
print();
dem++;
}
}
void tim()
{
int i, q;
for (i=0; i<8; i++)
{
cot[i] = 1;
dong[i] = -1;
}
for (i=0; i<15; i++)
{
cheosac[i] = 1;
cheohuyen[i] = 1;
}
thu(0);
printf("\n Tong so cach dat quan Hau: %d",dem);
}
3. Tìm đường trong mê cung :
//Các biến toàn cục
//Ma trận đầu vào
int a[MAX][MAX] = {
{1,0,1,1,0,0},
{0,1,0,1,0,0},
{0,1,0,1,1,0},
{1,0,0,0,1,1},
{0,1,1,1,0,0},
{1,0,0,0,1,1},
};
//Mảng để đánh dấu những ô đã duyệt qua rồi (tránh lặp)
int mark[MAX][MAX];
//Cấp của ma trận
int n=6;
//Ngăn xếp lưu đường đi của lời giải
STACK path;
//Mảng lưu đường đi
POS kq[100];
int nk = 0;
//Kiểm tra xem đã đến đích hay chưa
int check(POS cur, int dir){
switch (dir){
case 0: if (cur.col==0) return 1;break;//left
case 1: if (!cur.row) return 1;break;//top
case 2: if (cur.col==MAX-1) return 1;break;//right
case 3: if (cur.row==MAX-1) return 1;break;//bottom
}
return 0;
}
//Khởi tạo toàn bộ mảng mark bằng 0
void initmark(){
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
mark[i][j]=0;
}
//Giải thuật đệ quy và quay lui để tìm đường đi
int findpath(POS cur, int dir)
{
if (check(cur,dir)) //đã đi được đến đích thì dừng
return 1;
//Thử 8 ô xung quanh ô đang đứng, xem có đi được tiếp ko
for(int i=1; i>=-1; i )
for(int j=1; j>=-1; j )
if ((i||j) && cur.row+i>=0 && cur.row+i<MAX
&& cur.col+j>=0 && cur.col+j<MAX){
POS p; //lưu ô tiếp theo có thể đi
p.row = cur.row+i;
p.col = cur.col+j;
if (a[p.row][p.col]==a[cur.row][cur.col] &&
!mark[p.row][p.col]){ //chưa đi và đi được
mark[p.row][p.col]=1; //đánh dấu là đã đi qua
int k=findpath(p,dir);//tiếp tục tìm đường
if (k) { //nếu đến được đích
push(path,p); //lưu p vào đường đi
return 1; //kết luận đi được
}
}
}
return 0;
}
//Giải thuật đệ quy và quay lui để tìm đường đi
void findpath2(POS cur, int dir)
{
if (check(cur,dir)) //đã đi được đến đích thì in kq
{
cout <<"Tim duoc duong di:\n";
for(int i=0; i<nk; i++)
cout <<"(" <<kq[i].row <<"," <<kq[i].col <<") >";
cout <<"end\n";
}
//Thử 8 ô xung quanh ô đang đứng, xem có đi được tiếp ko
for(int i=1; i>=-1; i )
for(int j=1; j>=-1; j )
if ((i||j) && cur.row+i>=0 && cur.row+i<MAX
&& cur.col+j>=0 && cur.col+j<MAX){
POS p; //lưu ô tiếp theo có thể đi
p.row = cur.row+i;
p.col = cur.col+j;
if (a[p.row][p.col]==a[cur.row][cur.col] &&
!mark[p.row][p.col]){ //chưa đi và đi được
mark[p.row][p.col]=1; //đánh dấu là đã đi qua
kq[nk++] = p;
findpath2(p,dir);//tiếp tục tìm đường
nk ; //quay lui, hủy đường đi thử
mark[p.row][p.col]=0; //hủy đánh dấu
}
}
}
4. Tìm đường trong đồ thị :
4.1 Giải thuật BFS:
void BFS(int a[][MAX], int n, int free[], int u){
int next[MAX], nn=0;
for(int v=0; v<n; v++) //tìm đỉnh kề chưa duyệt ttheo
if (a[u][v]==1 && free[v]==1){
cout <<v <<" ";
free[v] = 0; //đánh dấu đã duyệt qua rồi
next[nn++] = v;
}
for(int v=0; v<nn; v++)
BFS(a,n,free,next[v]); //duyệt tiếp
}
4.2 Giải thuật DFS:
void DFS(int a[][MAX], int n, int free[], int u){
cout <<u <<" "; //in kết quả
free[u] = 0; //đánh dấu đã duyệt qua rồi
for(int v=0; v<n; v++) //tìm đỉnh kề chưa duyệt ttheo
if (a[u][v]==1 && free[v]==1)
DFS(a,n,free,v); //duyệt tiếp từ đỉnh v
}
4.3 Đường đi ngắn nhất :
void timduong(int a[][MAX], int n, int u, int v)
{
if (u==v) { //tìm được đường đi đến đích
for(int i=0; i<np; i++) //in đường đi
cout <<path[i] <<" >";
cout <<tongcp <<endl;
if (mincp > tongcp) { //lưu đường đi ngắn nhất
mincp = tongcp;
nminp = np;
memcpy(minpath,path,np*sizeof(int));
}
}
for(int i=0; i<n; i++)
if (fr[i]==1 && a[u][i]!=0) {
fr[i] = 0;
path[np++] = i;
tongcp += a[u][i];
timduong(a,n,i,v);
fr[i] = 1;
np ;
tongcp -= a[u][i];
}
}
5. Bài toán tam giác số :
6. Bài toán hái táo :
//Hàm đệ quy quay lui để tìm đường
void tryit(int a[][MAX], int n, int row, int col){
if (col>n-1) { //đã đến đích
if (t > m) {
m = t;
memcpy(maxpath,path,n*sizeof(int)); //lưu đường đi
}
}
else {
for(int k=-1; k<=1; k++) //xét 3 vị trí
if (row+k>=0 && row+k<n){
t += a[row+k][col];
path[col] = row+k;
tryit(a,n,row+k,col+1); //đệ quy để đi tiếp
t -= a[row+k][col]; //trả lại để đi đường khác
}
}
}
//Hàm vét cạn để xét tất cả các khả năng
int vetcan(int a[][MAX], int n, int p[])
{
for(int i=0; i<n; i++)
tryit(a,n,i,0);
memcpy(p,maxpath,n*sizeof(int));
return m;
}
7. Sudoku:
#include "stdafx.h"
#include <stdio.h>
#define SIZE 9 //kích thước ô sudoku
#define DELTA 2
int a[SIZE+DELTA][SIZE+DELTA];
int n = SIZE;
int lastK;
void NhapData(); //nhập đề bài
void XuatKQ(); //xuất ma trận kết quả
void Try(int k);
int isOK(int i, int j, int x); //kiểm tra hợp lệ
int findLastK(); //tìm stt cuối cùng cấn điền
int _tmain(int argc, _TCHAR* argv[])
{
printf("TIM LOI GIAI BAI TOAN SUDOKU !!!\n");
NhapData();
lastK = findLastK();
printf("De bai:\n");
XuatKQ();
printf("Ket Qua:\n");
Try(0);
return 0;
}
//nhập dữ liệu
void NhapData()
{
int i, j, tmp;
FILE *fin = NULL;
fopen_s(&fin,"INPUT.TXT", "rt");
for (i=0; i<n; i++)
for (j=0; j<n; j++)
{
fscanf_s(fin, "%d", &tmp);
a[i][j] = tmp;
}
fclose(fin);
}
//xuất kết quả
void XuatKQ()
{
int i, j;
for (i=0; i<n; i++)
{
for (j=0; j<n; j++)
printf(" %d", a[i][j]);
printf("\n");
}
}
//hàm quay lui
void Try(int k)// số k là stt trong ma trận 0->80
{
int i, j, x;
while (a[k/n][k%n]!=0) //bỏ qua các ô đã điền
k++;
i = k/n; j = k%n;
for (x=1; x<=n; x++)
if (isOK(i, j, x)) //nếu trong phạm vi hàng ngang,hàng dọc và vùng 3X3
//của ô (i,j) ko chứa x
{
a[i][j] = x;//thử đặt ô đó = x
if (k==lastK)// nếu đây là ô cuối cùng cấn điền thì kết thúc
XuatKQ();
else //nếu chưa là ô cuối cùng
Try(k+1);//thử tìm lới giải ô tiếp theo
a[i][j] = 0; //trả lại để thử cách khác
}
}
//hàm kiểm tra xem trong phạm vi hàng ngang,hàng dọc và vùng 3X3 có chứa x ko
// có trả về 0 ngược lại trả về 1
int isOK(int i, int j, int x)
{
int k, t;
int tmpX, tmpY;
//kiểm tra hàng thứ i
for (k=0; k<n; k++)
if (a[i][k] == x)
return 0;
//kiểm tra cột thứ j
for (k=0; k<n; k++)
if (a[k][j] == x)
return 0;
//kiểm tra vùng 3x3
tmpX = i%3; tmpY = j%3;
for (k=i-tmpX; k<=i-tmpX+2; k++)
for (t=j-tmpY; t<=j-tmpY+2; t++)
if (a[k][t] == x)
return 0;
return 1;
}
//tìm vị trí chưa điền cuối cùng từ 0->80
int findLastK()
{
int i, j;
for (i=n-1; i>=0;i )
for (j=n-1; j>=0; j )
if (a[i][j]==0)
{
return (i*n + j);
}
}