遞歸與回溯:
2.八皇后問題:
- char board[10][10];
- void init()
- {
- int i = 0;
- int j = 0;
- for(i=0; i<N+2; i++)
- {
- board[0][i] = '#';
- board[N+1][i] = '#';
- board[i][0] = '#';
- board[i][N+1] = '#';
- }
- for(i=1; i<=N; i++)
- {
- for(j=1; j<=N; j++)
- {
- board[i][j] = ' ';
- }
- }
- }
- void display()
- {
- int i = 0;
- int j = 1;
- for(i=0; i<N+2; i++)
- {
- for(j=0; j<N+2; j++)
- {
- printf("%c", board[i][j]);
- }
- printf("\n");
- }
- }
- typedef struct _tag_pos //定義一個數據結構來充當方向
- {
- int i;
- int j;
- }Pos;
- /*檢測三個方向 左上 右上 正上 橫排是不檢測的 因爲一排只放一個*/
- static Pos pos[3] = {{-1,-1},{-1,1},{-1,0}};
- int check(int i, int j)
- {
- int p = 0;
- int ret = 1;
- for(p = 0; p < 3; p++) //檢測三個方向
- {
- int ni = i;
- int nj = j;
- while(ret && (board[ni][nj] != '#'))//判斷沒有到達棋盤邊界
- {
- ni = ni + pos[p].i;
- nj = nj + pos[p].j;
- ret = ret && (board[ni][nj] != '*');//判斷這個方向沒有放過皇后
- }
- }
- return ret; //可以放皇后返回1 不可返回0
- }
- void find(int i)
- {
- int j = 0;
- if(i > N) //判斷是否已經超過了第八行
- {
- coust++; //計算八皇后情況的個數
- display();
- //getchar();
- }
- else
- {
- for(j = 1; j <= N; j++) //判斷一行 是否有匹配的位置
- {
- if(check(i,j))
- {
- board[i][j] = '*'; //放置皇后
- find(i+1);
- board[i][j] = ' '; //清除放錯的皇后
- }
- }
- }
- }
看着上面的動態想象下,當有時候,出現過的皇后又消失了,就是因爲for循環結束了,還沒有check成功,導致遞歸結束,返回到上層遞歸,並且擦除上層皇后的位置,並且繼續for循環,如果這層for中check依然不成功,繼續回溯,這個消失的過程就是回溯過程!與動圖不同的是,我們的程序,不會在找完一種情況後就結束!即使成功匹配,程序也會向上層回溯,去尋找其它的情況,直到第一行for循環結束(即 i=1 的時候),程序纔會停止!
本節代碼:
八皇后問題的完整代碼:- #include <stdio.h>
- #define N 8
- static char board[N+2][N+2];
- static int coust = 0; //記錄八皇后個數
- typedef struct _tag_pos //定義一個數據結構來充當方向
- {
- int i;
- int j;
- }Pos;
- /*檢測三個方向 左上 右上 正上 橫排是不檢測的 因爲一排只放一個*/
- static Pos pos[3] = {{-1,-1},{-1,1},{-1,0}};
- void init()
- {
- int i = 0;
- int j = 0;
- for(i=0; i<N+2; i++)
- {
- board[0][i] = '#';
- board[N+1][i] = '#';
- board[i][0] = '#';
- board[i][N+1] = '#';
- }
- for(i=1; i<=N; i++)
- {
- for(j=1; j<=N; j++)
- {
- board[i][j] = ' ';
- }
- }
- }
- void display()
- {
- int i = 0;
- int j = 1;
- for(i=0; i<N+2; i++)
- {
- for(j=0; j<N+2; j++)
- {
- printf("%c ", board[i][j]);
- }
- printf("\n");
- }
- }
- int check(int i, int j)
- {
- int p = 0;
- int ret = 1;
- for(p = 0; p < 3; p++) //檢測三個方向
- {
- int ni = i;
- int nj = j;
- while(ret && (board[ni][nj] != '#'))//判斷沒有到達棋盤邊界
- {
- ni = ni + pos[p].i;
- nj = nj + pos[p].j;
- ret = ret && (board[ni][nj] != '*');//判斷這個方向沒有放過皇后
- }
- }
- return ret; //可以放皇后返回1 不可返回0
- }
- void find(int i)
- {
- int j = 0;
- if(i > N) //判斷是否已經超過了第八行
- {
- coust++; //計算八皇后情況的個數
- display();
- //getchar(); //起到斷點的作用
- }
- else
- {
- for(j = 1; j <= N; j++) //判斷一行 是否有匹配的位置
- {
- if(check(i,j))
- {
- board[i][j] = '*'; //放置皇后
- find(i+1);
- board[i][j] = ' '; //清除放錯的皇后
- }
- }
- }
- }
- int main()
- {
- init();
- //display();
- find(1);
- printf("coust is %d \n",coust);
- return 0;
- }