phương pháp quay lui trong kĩ thuật lập trình nêu ra các ví dụ minh họa code từng bài mẫu các code được chạy thử trước khi được đưa vào word đồng thời cũng được sự kiểm tra của thầy trước khi làm tài kiệu
Trang 1THUẬ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
Trang 2{
//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];
Trang 3if (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 )
{
Trang 4int 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;
Trang 5//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
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 )
Trang 6if ((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) {
Trang 7fr[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
Trang 8int _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 )// 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
{
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
}
}
Trang 9//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 , int , int )
{
int k, t;
int tmpX, tmpY;
for (k=0; k<n; k++)
if (a[i][k] == x
return 0;
for (k=0; k<n; k++)
if (a[k][j] == x
return 0;
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);
}
}