DFS(深度优先搜索)算法在蓝桥杯中属于必考知识点。
DFS的代码框架
ans; //答案,常常用全局变量表示
void dfs(层数,其他参数){
if (到达目的地、或者出局){ //到达最底层,或者满足条件退出
更新答案ans; //答案一般用全局变量表示,ans是最优解
return; //递归返回,即返回到上一层
}
(剪枝) //在进一步DFS之前剪枝
for (用i遍历下一层所有可能的情况) //对每一个情况继续DFS
if (used[i] == 0) { //如果状态i没有处理过,就可以进入下一层dfs
used[i] = 1; //标记状态i为已经使用,在后续dfs时不能再使用
dfs(层数+1,其他参数); //下一层,即搜小规模后继续dfs
used[i] = 0; //恢复状态i,回溯时,不影响上一层对这个状态的使用
}
return; //返回到上一层
}
DFS与排列
1.全排列问题
#include<iostream>
using namespace std;
const int N = 100;
int n;
int vis[N],p[N];
void dfs(int k)
{
if(k==n+1)
{
for(int i = 1; i <= n; i++)
{
printf("%5d",p[i]);
}
cout<<endl;
return;
}
for(int i = 1; i <= n; i++)
{
if(vis[i]==0)
{
vis[i] = 1;
p[k] = i;
dfs(k+1);
vis[i] = 0;
}
}
}
int main()
{
cin>>n;
dfs(1);
return 0;
}
2.部分排列问题
如果需要打印n
个数中任意m
个数的排列,略作修改即可。例如n=4,m=3
,k=n+1
改为step=m+1
,i<=n
改为i<=m
。
#include<iostream>
using namespace std;
const int N = 100;
int n,m;
int vis[N],p[N];
void dfs(int k)
{
if(k==m+1)
{
for(int i = 1; i <= m; i++)
{
cout<<p[i]<<" ";
}
cout<<endl;
}
for(int i = 1; i <= n; i++)
{
if(vis[i]==0)
{
vis[i] = 1;
p[k] = i;
dfs(k+1);
vis[i] = 0;
}
}
}
int main()
{
cin>>n>>m;
dfs(1);
return 0;
}
DFS与连通性
DFS判断连通性,步骤如下:
- 从任意一个点u开始遍历,标记u已经搜过。一般从第一个点开始。
- DFS搜索u的所有符合连通条件的邻居点。已经搜过的点标记为已经搜过,后面不用再搜。扩展u的邻居点时,应该判断这个邻居点是不是在边界内。
- DFS结束,找到了与u连通的所有点,这是一个连通块。
- 不与u连通的、其他没有访问到的点,继续用上述步骤处理,找到所有的连通块。
#include<iostream>
#include<cmath>
using namespace std;
#define int long long
#define endl '\n'
typedef long long ll;
int dx[4] = { 0,1,0,-1 }, dy[4] = { 1,0,-1,0 };
int n= 30, m = 60;
char g[100][100];
int dfs(int x, int y)
{
if (g[x][y] == '0') return 0;//递归出口
g[x][y] = '0';//把‘1’改为‘0’,之后不再搜索
int cnt = 1;
for (int i = 0; i < 4; i++)
{
int xx = x + dx[i], yy = y + dy[i];
if (xx < 0 || yy < 0 || xx >= n || yy >= m) continue;
cnt += dfs(xx, yy);//累计连通块的大小
}
return cnt;
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
for (int i = 0; i < 30; i++) cin >> g[i];
int ans = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (g[i][j] == '1')
ans = max(ans, dfs(i, j));//如果是‘1’,就dfs并更新答案
}
}
cout << ans << endl;
return 0;
}
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
#define endl '\n'
typedef long long ll;
const int N = 1010;
int dx[4] = { 0,1,0,-1 }, dy[4] = { 1,0,-1,0 };
char g[N][N];
int vis[N][N] = { 0 };
int flag;//是否被淹
void dfs(int x, int y)
{
vis[x][y] = 1;//搜过了
if (g[x][y + 1] == '#' && g[x + 1][y] == '#' && g[x - 1][y] == '#' && g[x][y - 1] == '#')
{
flag = true;//不会被淹
}
for (int i = 0; i < 4; i++)
{
int xx = x + dx[i], yy = y + dy[i];
if (vis[xx][yy] == 0 && g[xx][yy] == '#')
dfs(xx, yy);
}
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> g[i];
int ans = 0;//被淹的个数
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
if (vis[i][j] == 0 && g[i][j] == '#')
{
flag = 0;//假设被淹
dfs(i, j);
if (flag == 0)ans++;
}
}
}
cout << ans << endl;
return 0;
}