DFS模板以及例項——油田(用DFS求連通塊)
阿新 • • 發佈:2018-12-22
首先是DFS模板套路:
void DFS(...)//v是頂點 { 訪問結點相關操作; for(從結點的第一個相鄰接點;結點沒有相鄰接點了即終止條件;下一個相鄰結點) { if(相鄰結點滿足條件如未訪問過) { 對相鄰結點呼叫DFS(); } } } int main() { 初始化是否訪問標記; for(int v=xxx;v<Vnum;v++){//xxx表示從第xxx個頂點開始遍歷,第xxx個結點是一個連通分量的任一結點。 //呼叫一次DFS為訪問了圖的一個連通分量的所有結點 //若已知圖為連通的,則不需for迴圈,直接呼叫DFS()即可 if(滿足條件如為訪問過) { 呼叫DFS(); } } return 0; }
例題:
油田(Oil Deposits, UVa 572,ZOJ1709,POJ1562)
輸入一個m行n列的字元矩陣,統計字元“@”組成多少個八連塊。如果兩個字元“@”所在的格子相鄰(橫、豎或者對角線方向),就說它們屬於同一個八連塊。例如,下圖中有兩個八連塊。
輸入描述:
輸入檔案中包含多個測試資料,每個測試資料描述了一個網格。每個網格資料的第1行為兩個整數:m、n,分別表示網格的行和列;如果m=0,則表示輸入結束,否則1<=m<=100,1<=n<=100。接下來有m行資料,每行資料有n個字元(不包括行結束符)。每個字元代表一個小方塊,如果為“*”,則代表沒有石油,如果為“@”,則代表有石油,是一個pocket。
輸出描述:
對輸入檔案中的每個網格,輸出網格中不同的油田數目。如果兩塊不同的pocket在水平、垂直或者對角線方向上相鄰,則被認為屬於同一塊油田。每塊油田所包含的pocket數目不會超過100。
樣例輸入:
5 5
****@
*@@*@
*@**@
@@@*@
@@**@
樣例輸出:
2
本題程式碼:
/*注意要求多組輸入*/ #include<iostream> #include<cstring>//memset在這個標頭檔案裡 using namespace std; #define max 100+5 char a[max][max];//油田 int visited[max][max]; int m,n; //現在位置x,y void dfs(int x,int y) { visited[x][y]=1;//將現在的位置變為已訪問過 for(int i=-1;i<=1;i++) { for(int j=-1;j<=1;j++) {//迴圈遍歷移動的八個方向 int nx=x+i,ny=y+j;//向x方向移動i,向y方向移動j if(nx>=0&&nx<=m-1&&ny>=0&&ny<=n-1&&visited[nx][ny]==0&&a[nx][ny]=='@')//若下一個位置在園子內並且沒被訪問過並且是油田 { dfs(nx,ny); } } } return; } int main() { while(cin>>m>>n) { int res=0;//進行dfs的次數,即為圖的連通分量的個數 if(m==0) break; memset(visited,0,sizeof(visited));//將visited陣列全初始化為0,表示沒訪問過;1表示已訪問過 for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { cin>>a[i][j]; } } for(int i=0;i<m;i++) { for(int j=0;j<n;j++)//從有油田@開始dfs { if(visited[i][j]==0&&a[i][j]=='@') { dfs(i,j); res++; } } } cout<<res<<endl; } return 0; }
另一種DFS模板套路:
void dfs(int step)
{
if(邊界成立)
{
。。。。(相關操作)
return;
}
for(嘗試每一種可能)
{
把這種可能標記表示走過
。。。。(相關操作)
繼續下一步dfs(step+1);
把這種可能標記去除
}
return;
}
本題另一種程式碼:
#include<iostream>
#include<cstring>
using namespace std;
#define max 1000+5
int m,n;
int visited[max][max];
char a[max][max];
void dfs(int x,int y)
{
if(x<0||x>=m||y<0||y>=n||visited[x][y]==1||a[x][y]!='@')
return;
visited[x][y]=1;
for(int i=-1;i<=1;i++)
{
for(int j=-1;j<=1;j++)
{
int nx=x+i,ny=y+j;
dfs(nx,ny);
}
}
}
int main()
{
while(cin>>m>>n)
{
if(m==0)
break;
int res=0;
memset(visited,0,sizeof(visited));//將visited陣列全初始化為0,表示沒訪問過;1表示已訪問過.一定不要忘記初始化!!!因為是全域性變數,每一次一定要把visited陣列都初始化為0且a陣列以及m,n重新輸入的
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
cin>>a[i][j];
}
}
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(visited[i][j]==0&&a[i][j]=='@')
{
dfs(i,j);
res++;
}
}
}
cout<<res<<endl;
}
return 0;
}