Tải bản đầy đủ (.docx) (9 trang)

phương pháp quay lui trong kĩ thuật lập trình

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 (86.97 KB, 9 trang )

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);
}
}

×