輸入一個n*n的黑白圖像(1表示黑色,0表示白色),任務是統計其中八連塊的個數。如果兩個黑格子有公共邊或者公共頂點,就說它們屬於同一個八連塊。如圖6-11所示的圖形有3個八連塊。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
圖6-11 擁有3個八連塊的黑白圖形
【分析】
用遞歸求解:從每個黑格子出發,遞歸訪問它所有的相鄰黑格。
int mat[MAXN][MAXN], vis[MAXN][MAXN]; void dfs(int x, int y) { if(!mat[x][y] || vis[x][y]) return; // 曾經訪問過這個格子,或者當前格子是白色 vis[x][y] = 1; // 標記(x,y)已訪問過 dfs(x-1,y-1); dfs(x-1,y); dfs(x-1,y+1); dfs(x-1,y); dfs(x,y+1); dfs(x+1,y-1); dfs(x+1,y); dfs(x+1,y+1); // 遞歸訪問周圍的八個格子 } 這裏,黑格(x,y)的mat[x][y]爲1,白格爲0。爲了避免同一個格子訪問多次,用標誌vis[x][y]記錄格子(x,y)是否訪問過。在輸入之前,在迷宮的外面加上一圈虛擬的白格子,見下面的程序。 memset(mat, 0, sizeof(mat)); //所有格子都初始化爲白色,包括周圍一圈的虛擬格子 memset(vis, 0, sizeof(vis)); // 所有格子都沒有訪問過 scanf("%d", &n); for(int i = 0; i < n; i++) { scanf("%s", s); for(int j = 0; j < n; j++) mat[i+1][j+1] = s[j]-'0'; // 把圖像往中間移動一點,空出一圈白格子 }
接下來,只需不斷找黑格,然後調用dfs。從它出發尋找八連塊:
int count = 0; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) if(!vis[i][j] && mat[i][j]) { count++; dfs(i,j); } //找到沒有訪問過的黑格 printf("%d\n", count);
完整的程序如下:
#include <stdio.h> #include <string.h> const int MAXN = 1000; int n; int mat[MAXN][MAXN], vis[MAXN][MAXN]; void dfs(int x, int y) { if(!mat[x][y] || vis[x][y]) return; //曾經訪問過這個格子,或者當前 格子是白色 vis[x][y] = 1; // 標記(x,y)已訪問過 dfs(x-1,y-1); dfs(x-1,y); dfs(x-1,y+1); dfs(x-1,y); dfs(x,y+1); dfs(x+1,y-1); dfs(x+1,y); dfs(x+1,y+1); // 遞歸訪問周圍的八個格子 } int main() { char s[MAXN + 10]; memset(mat, 0, sizeof(mat)); // 所有格子都初始化爲白色,包括周圍 一圈的虛擬格子 memset(vis, 0, sizeof(vis)); // 所有格子都沒有訪問過 scanf("%d", &n); for(int i = 0; i < n; i++) { scanf("%s", s); for(int j = 0; j < n; j++) mat[i+1][j+1] = s[j]-'0'; // 把圖像往中間移動一點,空出一圈白格子 } int count = 0; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) // 找到沒有訪問過的黑格 if(!vis[i][j] && mat[i][j]) { count++; dfs(i,j); } printf("%d\n", count); return 0; }
上面的函數dfs就是深度優先遍歷(Depth-FirstSearch,DFS)的算法,DFS和BFS一樣,都是從一個結點出發,按照某種特定的次序訪問圖中的其他特點。不同的是,BFS使用隊列來存放待擴展結點,而DFS使用的是棧。
附:我自己理解後敲的代碼:
#include <stdio.h> #include <string.h> #include<algorithm> #include<iostream> #define M 1020 using namespace std; int n; int i,j; char map[M][M]; void dfs(int x,int y) { if(map[x][y]!='1'||x<0||y<0||x>=n||y>=n) return; //曾經訪問過這個格子,或者當前格子是白色 else { map[x][y] = '0'; // 標記(x,y)已訪問過 dfs(x-1,y-1); dfs(x-1,y+1); dfs(x-1,y); dfs(x,y+1); dfs(x,y-1); dfs(x+1,y-1); dfs(x+1,y); dfs(x+1,y+1); // 遞歸訪問周圍的八個格子 } } int main() { memset(map, 0, sizeof(map)); // 所有格子都沒有訪問過 scanf("%d", &n); for(i=0; i<n; i++) for(j=0; j<n; j++) cin>>map[i][j]; int count = 0; for(i = 0; i <n; i++) for(j = 0; j <n; j++) { // 找到沒有訪問過的黑格 if(map[i][j]=='1') { dfs(i,j); count++; } } printf("%d\n", count); return 0; } /* 6 100100 001010 000000 110000 111000 010100 */