150 likes | 310 Views
מבוא למדעי המחשב. backtracking. מוטיבציה. בעיית n המלכות: נתון: לוח שחמט בגודל . המטרה: לסדר על הלוח n מלכות כך שאף אחת לא תאיים על השנייה. דוגמא: עבור 2 מלכות, לא קיים פתרון. Q. Q. Q. Q. Q. Q. מוטיבציה. בעיית n המלכות: דוגמא: פתרון אפשרי עבור 4 מלכות.
E N D
מבוא למדעי המחשב backtracking
מוטיבציה בעיית n המלכות: נתון: לוח שחמט בגודל . המטרה: לסדר על הלוח n מלכות כך שאף אחת לא תאיים על השנייה. דוגמא: עבור 2 מלכות, לא קיים פתרון. Q Q
Q Q Q Q מוטיבציה בעיית n המלכות: דוגמא: פתרון אפשרי עבור 4 מלכות.
בעיית n המלכות פתרון אפשרי: • לבדוק את כל האפשרויות: עבור n מלכות מספר האפשרויות הוא: עבור n=4←43,680 אפשרויות. עבור n=8← 178,462,987,637,760אפשרויות.
Q Q בעיית n המלכות • פתרון אפשרי: לבדוק את כל האפשרויות. • החיסרון: מעבר שיטתי על קבוצת כל המיקומים האפשריים מתייחס לכל פתרון בנפרד ולא מבחין בפתרונות בעלי מכנה משותף שיכלו להיבדק (ולהיפסל !) כמקשה אחת בשלב מוקדם. דוגמא:
Backtracking הרעיון: • בניית הפתרונות האפשריים בצורה שיטתית. • בכל שלב מנסים ללכת צעד אחד קדימה. • במידה ומתאפשר ממשיכים. במידה ולא – חוזרים לשלב הקודם ומנסים לבחור בצעד אחר. למשל, עבור בעיית n המלכות: • ברור כי עלינו למקם בכל שורה בדיוק מלכה אחת. נעבור על השורות לפי הסדר. • עבור השורה ה- i : ננסה למקם את המלכה כך שלא תאיים על המלכות בשורות 1,…,i-1. • אם נצליח, נמשיך לשורה הבאה. • אם לא, נחזור לשורה הקודמת ונשנה את מיקום המלכה שם. • נחזור על התהליך באופן רקורסיבי עד למציאת כל הפתרונות.
בעיית n המלכות – פתרון בעזרת backtracking /* queens.c */ /* print all solutions of the 8 (N) queens problem */ #include <stdio.h> #define N 5 enum {EMPTY,QUEEN}; enum {FALSE, TRUE}; void solve (char board[N][N], int row); void print_board (char board[N][N]); int threatens (char board[N][N], int row, int column); int main() { char board[N][N]; int i,j; /* initialize board to empty */ for (i=0; i<N; i++) { for (j=0; j<N; j++) { board[i][j]=EMPTY; } } solve(board,0); return 0; }
בעיית n המלכות – פתרון בעזרת backtracking void solve (char board[N][N], int row) { int column=0; if (row == N) { print_board(board); } else { for (column=0; column < N; column++) { if (!threatens(board, row, column)) { board[row][column] = QUEEN; solve(board, row+1); board[row][column] = EMPTY; } } } return; }
בעיית n המלכות – פתרון בעזרת backtracking void print_board(char board[N][N]) { int i,j; static int counter=0; printf("Solution number %d:\n", ++counter); for (i=0; i<N; i++) { for (j=0; j<N; j++) { printf("%s", (board[i][j]==EMPTY)?" . ":" Q "); } printf("\n"); } printf("\n"); }
בעיית n המלכות – פתרון בעזרת backtracking /* threatens: return TRUE if "board" has a queen which threatens position [row,column] */ int threatens(char board[N][N], int row, int column) { int r; /* check if there's a queen on this column */ for (r=0; r<row; r++) { if (board[r][column] == QUEEN) { return TRUE; } } /* check if there's a queen on the diagonals */ /* first, check the upper-left diagonal: [row-r,column-r] */ for (r=1; row-r>=0 && column-r>=0; r++) { if (board[row-r][column-r] == QUEEN) { return TRUE; } } /* then, check the upper-right diagonal: [row-r,column+r] */ for (r=1; row-r>=0 && column+r<N; r++) { if (board[row-r][column+r] == QUEEN) { return TRUE; } } return FALSE; }
Q Q Q Q בעיית n המלכות – פתרון בעזרת backtracking שיפור הפתרון: במקום לייצג את הלוח ע"י טבלה (מערך דו-מימדי) ניתן להיעזר במערך חד-מימדי כאשר בתא ה- i יימצא אינדקס העמודה בה ממוקמת המלכה בשורה ה- i. 0 1 2 3 2 0 0 0 1 1 3 2 2 1 3 3
בעיית n המלכות – פתרון בעזרת backtracking /* queens1.c */ /* print all solutions of the 8 (N) queens problem */ #include <stdio.h> #define N 8 enum {EMPTY,QUEEN}; enum {FALSE,TRUE}; void solve (char board[N], int row); void print_board (char board[N]); int threatens (char board[N], int column); int main() { static char board[N]; solve(board,0); return 0; }
בעיית n המלכות – פתרון בעזרת backtracking void solve (char board[N], int row) { int col; if (row == N) { print_board(board); } else { for (col=0; col < N; col++) { board[row] = col; if (!threatens(board, row)) { solve(board, row+1); } } } return; }
בעיית n המלכות – פתרון בעזרת backtracking void print_board(char board[N]) { int i,j; static int counter=0; printf("Solution number %d:\n", ++counter); for (i=0; i<N; i++) { for (j=0; j<N; j++) { printf("%s", (board[i]==j)?" Q ":" . "); } printf("\n"); } printf("\n"); }
בעיית n המלכות – פתרון בעזרת backtracking /* threatens: return TRUE if "board" has a queen which threatens position [row,column] */ int threatens(char board[N], int row) { int i; for (i=0; i<row; i++) { /* check if there's a queen on this column */ if ( board[i] == board[row] ) { return TRUE; } /* check upper-right diagonal */ if ( board[i] == board[row] + (row-i) ) { return TRUE; } /* check upper-left diagonal */ if ( board[i] == board[row] - (row-i) ) { return TRUE; } } return FALSE; }