一篇文章帶你快速入門DFS深度優先搜索

目錄

深度優先搜索:

框架展示:

例一、中國象棋

例二、迷宮

例三、迷宮解的方案數

例四、最大的蛋糕塊

例五、家譜

例六、馬的覆蓋點

例七、王子救公主

例八、開公司


深度優先搜索:

深度優先搜索屬於圖算法的一種,英文縮寫爲DFS即Depth First Search.其過程簡要來說是對每一個可能的分支路徑深入到不能再深入爲止,而且每個節點只能訪問一次。

深度優先遍歷圖的方法是,從圖中某頂點v出發:
(1)訪問頂點v;
(2)依次從v的未被訪問的鄰接點出發,對圖進行深度優先遍歷;直至圖中和v有路徑相通的頂點都被訪問;
(3)若此時圖中尚有頂點未被訪問,則從一個未被訪問的頂點出發,重新進行深度優先遍歷,直到圖中所有頂點均被訪問過爲止。

框架展示:

例一、中國象棋

題目描述:

代碼如下:

#include<cstdio>
char map[10][10];
bool f;
int visited[10][10];          //字符串長度爲9,至少要開10的長度,因爲有'\0'
int dir[8][2]={{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2}};
bool in(int x,int y){        //判斷是否在棋盤內
	if(x>=0&&x<10&&y>=0&&y<9)
		return true;
	return false;
}
void dfs(int x,int y){
	visited[x][y]=1;    //標記已訪問
	if(f){              //已跳到馬需要跳到的位置 
		return;
	}
	if(map[x][y]=='T'){ //找到馬需要跳到的位置   
		f=true;
		return;
	}
	for(int i=0;i<8;++i){        
		int tx=x+dir[i][0];
		int ty=y+dir[i][1];
		if(in(tx,ty)&&map[x][y]!='#'&&!visited[tx][ty])
			dfs(tx,ty);
	}
}
int main(){
	int x,y;
	for(int i=0;i<10;++i)
		scanf("%s",map[i]);
	for(int i=0;i<10;++i){
		for(int j=0;j<9;++j){
			if(map[i][j]=='S'){
				x=i;
				y=j;
				break;
			}
		}	
	}
	dfs(x,y);
	if(f)
		printf("Yes\n");
	else
		printf("No\n");
	return 0;
}

運行結果:

例二、迷宮

題目描述:

輸入:

第一行爲行列數n和m

其餘n行輸入n*m的地圖

輸出:

迷宮起點到終點最短路徑 

代碼如下:

#include<iostream>
#include<string> 
using namespace std;
int n,m;
int ans=10000000;
string maze[110];
bool visited[110][110];
int dire[4][2]={{0,-1},{-1,0},{0,1},{1,0}};
bool in(int x,int y){
	if(x>=0&&x<n&&y>=0&&y<m)
		return true;
	return false;
}
bool dfs(int x,int y,int step){
	if(maze[x][y]=='T'){
		if(step<ans){
			ans=step;	
		}
		return true; 
	}
	visited[x][y]=1;	
	for(int i=0;i<4;++i){
		int tx=x+dire[i][0];
		int ty=y+dire[i][1];
		if(in(tx,ty)&&maze[tx][ty]!='*'&&!visited[tx][ty]){
			dfs(tx,ty,step+1);
		}
	}
	visited[x][y]=0;
	return false;
}
int main(){
	cin>>n>>m;
	for(int i=0;i<n;++i)
		cin>>maze[i];
	int x,y;
	for(int i=0;i<n;++i){
		for(int j=0;j<m;++j){
			if(maze[i][j]=='S'){
				x=i;
				y=j;
			}
		}
	}
	dfs(x,y,0);
	cout<<ans<<endl;
	return 0;;
} 

 運行結果:

例三、迷宮解的方案數

題目描述:

輸出:

從起點到達終點的路徑的條數

代碼如下:

#include<cstdio>
int n,m,x,y,ans;
char map[15][15];
bool visited[15][15];
void dfs(int x,int y){
	if(x<0||x>=n||y<0||y>=m||visited[x][y]||map[x][y]=='#')
		return;
	if(map[x][y]=='e'){
		++ans;
		return;
	}
	visited[x][y]=1;
	dfs(x-1,y);
	dfs(x+1,y);
	dfs(x,y-1);
	dfs(x,y+1);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;++i)
		scanf("%s",map[i]);
	for(int i=0;i<n;++i){
		for(int j=0;j<m;++j){
			if(map[i][j]=='s'){
				x=i;
				y=j;
			}
		}
	}
	dfs(x,y);
	printf("%d\n",ans);
	return 0;
}

運行結果:

例四、最大的蛋糕塊

題目描述:

輸入:

第一行爲蛋糕的行列數n,m

其餘n行爲蛋糕

輸出:

蒜頭君最大可以喫到的蛋糕佔據的網格數

代碼如下:

#include<cstdio>
int n,m,cnt,ans;
char map[1005][1005];
bool visited[1005][1005];
void dfs(int x,int y){
	if(x<0||x>=n||y<0||y>=m||visited[x][y]||map[x][y]=='.')
		return;
	visited[x][y]=1;
	++cnt;
	dfs(x-1,y);
	dfs(x+1,y);
	dfs(x,y-1);
	dfs(x,y+1);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;++i)
		scanf("%s",map[i]);
	for(int i=0;i<n;++i){
		for(int j=0;j<m;++j){
			if(!visited[i][j]&&map[i][j]=='#'){
				cnt=0;
				dfs(i,j);
				if(cnt>ans)
					ans=cnt;
			}
		}
	}
	printf("%d\n",ans);
} 

運行結果:

例五、家譜

題目描述:

輸出:

輸出n行,每行有一個整數,表示第i個人有多少個直系後代

代碼如下:

#include<cstdio>
#include<vector> 
using namespace std;
vector<int> son[100005];
int ans[100005];
bool f[100005];
int dfs(int u){
	int ret=0;
	for(int i=0;i<son[u].size();++i)
		ret+=dfs(son[u][i]);
	ans[u]=ret;
	return ret+1;
}
int main(){
	int n,x,y,u;
	scanf("%d",&n);
	for(int i=0;i<n-1;++i){
		scanf("%d%d",&x,&y);
		son[x].push_back(y);
		f[y]=1;
	}
	for(int i=1;i<=n;++i){
		if(!f[i]){
			u=i;
			break;
		}
	}
	dfs(u);
	for(int i=1;i<=n;++i)
		printf("%d\n",ans[i]);
	return 0;	
}

運行結果:

另附(vector講解):

競賽常用STL內置函數用法解析——六、vector

例六、馬的覆蓋點

題目描述:

輸入:

第一行輸入兩個整數 n (1 ≤ x ≤ 100), m(1≤ m ≤ 100) 代表棋盤行和列的大小。
第二行輸入兩個整數 x (1 ≤ x ≤ n), y (1 ≤ y ≤ m) 代表馬開始所的位置。

輸出:

輸出整個棋盤,'.'代表棋盤上可以落子的點。'#'這個代表馬三步能到達的點。

代碼如下:

#include<cstdio>
char s[105][105];
int n,m;
int dir[8][2]={{-2,-1},{-2,1},{2,-1},{2,1},{1,2},{1,-2},{-1,2},{-1,-2}};
void dfs(int x,int y,int step){
	if(step>3)
		return;
	if(x<0||x>=n||y<0||y>=m)
		return;
	s[x][y]='#';
	for(int i=0;i<8;++i)
		dfs(x+dir[i][0],y+dir[i][1],step+1);
}
int main(){
	int x,y;
	scanf("%d%d%d%d",&n,&m,&x,&y);
	for(int i=0;i<n;++i){
		for(int j=0;j<m;++j){
			s[i][j]='.';
		}
	}
	dfs(x-1,y-1,0);
	for(int i=0;i<n;++i)
		printf("%s\n",s[i]);
	return 0;
}  

運行結果:

例七、王子救公主

題目描述:

代碼如下:

#include<cstdio>
int n,m;
char map[105][105];
bool visited[105][105][2];
void dfs(int x,int y,int d){
	if(x<0||x>=n||y<0||y>=m||visited[x][y][d]||map[x][y]=='#')
		return;
	visited[x][y][d]=1;
	dfs(x-(2-d),y,d);
	dfs(x+(2-d),y,d);
	dfs(x,y-(2-d),d);
	dfs(x,y+(2-d),d);
}
int main(){
	int x,y;
	bool ans;
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;++i){
		scanf("%s",map[i]);
	}
	for(int i=0;i<n;++i){
		for(int j=0;j<m;++j){
			if(map[i][j]=='w'){
				x=i;
				y=j;
				break;
			}
		}
	}
	dfs(x,y,0);		//0爲王子走2步,1爲公主走1步 
	ans=0;
	for(int i=0;i<n;++i){
		for(int j=0;j<m;++j){
			if(map[i][j]=='g'){
				x=i;
				y=j;
				break;
			}
		}
	}
	dfs(x,y,1);
	for(int i=0;i<n;++i){
		for(int j=0;j<m;++j){
			if(visited[i][j][0]&&visited[i][j][1]){
				ans=true;
			}
		}
	}
	if(ans)
		printf("yes\n");
	else
		printf("no\n;");
	return 0;
}

運行結果:

例八、開公司

題目描述:

代碼如下:

#include<cstdio>
int task[15][15];
bool visited[15];
int n,ans;
void dfs(int x,int t){
	if(x==n){
		if(t<ans)
			ans=t;
		return;
	}
	for(int i=0;i<n;++i){
		if(!visited[i]){
			visited[i]=1;
			dfs(x+1,t+task[x][i]);
			visited[i]=0;
		}
	}
}
int main(){
	scanf("%d",&n);
	for(int i=0;i<n;++i){
		for(int j=0;j<n;++j)
			scanf("%d",&task[i][j]);
	}
	ans=20000;
	dfs(0,0);
	printf("%d\n",ans);
	return 0;
}

運行結果:

另附(此題類似於藍橋杯:組隊):

藍橋杯真題詳細題解——持續更新

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章