近期着手参加2024年蓝桥杯A组省赛,跟随罗勇军老师的20周备赛博客进行学习,对博客中的题目进行学习、整理、编写此博客,目的为与大家广泛交流!
罗永军老师20周蓝桥杯训练计划https://blog.csdn.net/weixin_43914593/article/details/133951894
目录
1 全排列问题
-
题目链接
-
代码
#include<bits/stdc++.h> using namespace std; int n; int a[10]; int b[10]; int vis[10]; void dfs(int step){ if(step == n + 1){ for(int i = 1;i <= n;i++){ printf("%5d",b[i]);//场宽一会看一下啥意思 } cout<<endl; return; } for(int i = 1;i <= n;i++){ if(vis[i] == 0){ b[step] = a[i]; vis[i] = 1;//标记 dfs(step + 1); vis[i] = 0;//回溯 } } return; } int main(){ cin>>n; for(int i = 1;i <= n;i++) a[i] = i; dfs(1); return 0; }
-
题解
step代表此次DFS正在放入第step个数字。我们要求n个数字全排列,当step达到n + 1时,我们这一排列完成。 vis[]对数字进行标记,vis[i] = 1,代表该排列中存在i;vis[i] = 0,代表该排列不存在i。对于存在的我们不再放入,不存在的可以放入。 第step个数字可以已经放入数字后,我们可以对第step个数字放入新的数字,调用DFS(step + 1),调用后进行回溯,此数字不再被放入排列中。
2 最大连通
-
题目链接
-
代码
//最大连通 #include<bits/stdc++.h> using namespace std; char a[40][70];//30行,60列 //dx,dy可以合并出4个方向 int dx[4] = {-1,0,1,0}; int dy[4] = {0,1,0,-1}; long long ans; long long dfs(int x,int y){ cerr<<x<<" "<<y<<endl; if(a[x][y] == '0') return 0; int ans = 1; a[x][y] = '0'; for(int i = 0;i < 4;i++){ int nx = x + dx[i],ny = y + dy[i]; if(nx < 0 || ny < 0 || nx >= 30 || ny >= 60) continue; ans += dfs(nx,ny); } return ans; } int main(){ for(int i = 0;i < 30;i++){ cin>>a[i]; } for(int i = 0;i < 30;i++){ for(int j = 0;j < 60;j++){ if(a[i][j] == '1'){ ans = max(ans,dfs(i,j)); } } } cout<<ans<<endl; return 0; }
-
题解
地图长、宽固定:30行、60列。我们用char[][]接收。遍历每一位置,对没有搜索过且可连通的位置进行dfs搜索。 dfs搜索中,我们传入当前的x、y,将当前位置标记为0(代表我们已经搜索过),ans定为1。我们判定其四个方位是否可以继续连通,对可连通的位置继续调用dfs,判定其周边的四个方位是否连通。dfs在遇到当前位置为0(本就不连通或搜索过时),会返回0,同时不在继续调用dfs。 对ans进行累计,一层层递归进入,返回最终的ans值。
3 全球变暖
-
题目链接
-
代码
#include<bits/stdc++.h> using namespace std; const int N = 1e3 + 10; int n; char mp[N][N]; long long ans; int d[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; int vis[N][N]; bool flag; void dfs(int x,int y){ vis[x][y] = 1;//被搜过 if(mp[x + 1][y] == '#' && mp[x - 1][y] == '#' && mp[x][y + 1] == '#' && mp[x][y - 1] == '#'){ //cerr<<x<<" "<<y<<endl; flag = true;//有高地 } for(int i = 0;i < 4;i++){ int nx = x + d[i][0],ny = y + d[i][1]; if(vis[nx][ny] == 0 && mp[nx][ny] == '#'){ dfs(nx,ny); } } } int main(){ cin>>n; for(int i = 0;i < n;i++){ cin>>mp[i]; } for(int i = 0;i < n;i++){ for(int j = 0;j < n;j++){ if(mp[i][j] == '#' && vis[i][j] == 0){ flag = false;//回溯flag dfs(i,j); if(!flag) ans++; } } } cout<<ans<<endl; return 0; }
-
题解
在最大连通的基础上,多了一个判定问题,即当前岛屿是否会沉没。我们统计最终沉没岛屿数量; 解决方案,使用flag,对于不能沉默的岛屿,我们定flag = true;可以沉没的岛屿,我们定flag = false; 判定岛屿是否沉没的方法:判上下左右是否为'#',若连通块中的某个点满足此条件,则该岛屿不会沉没。
4 N皇后
-
题目链接
P1158 - 八皇后 - New Online Judge http://oj.ecustacm.cn/problem.php?id=1158
-
代码
#include<bits/stdc++.h> using namespace std; int tot;//记录方案数 int n; int ans[30];//第x行皇后放在第几列 int vis[30];//第y列放了皇后 int vis1[30];//主对角线放了皇后 int vis2[30];//副对角线放了皇后 void dfs(int x){ if(x == n + 1){ tot++; if(tot <= 3){ for(int i = 1;i <= n;i++){ cout<<ans[i]<<" "; } cout<<endl; } return; } for(int y = 1;y <= n;y++){ if(vis[y]) continue; if(vis1[x + y]) continue; if(vis2[x - y + n]) continue; ans[x] = y; vis[y] = 1;vis1[x + y] = 1;vis2[x - y + n] = 1; dfs(x + 1); vis[y] = 0;vis1[x + y] = 0;vis2[x - y + n] = 0; } } int main(){ cin>>n; dfs(1); cout<<tot<<endl; return 0; }
-
题解
本题属于dfs中排列组合 规律:主对角线vis1,x + y不变;副对角线vis2,x - y不变,我们实际使用时为保证数组下标 > 0,x - y + n不变;除此之外,只需判定该列是否存在皇后vis[]; 对于该列、主对角线、副对角线存在皇后的,我们不再放入;对于可以放入的,我们放入并标记。该排列组合完成后,需要进行回溯。退出条件为 n + 1,与排列组合一致,我们只需放入n个。