4.习题 4.1 acwing.1240. 完全二叉树的权值 第十届蓝桥杯省赛C++A/B组,第十届蓝桥杯省赛JAVAA组
给定一棵包含 NN 个节点的完全二叉树,树上每个节点都有一个权值,按从上到下、从左到右的顺序依次是
A1,A2,⋅⋅⋅ANA1,A2,···AN,如下图所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 输入格式 第一行包含一个整数 N。 第二行包含 N 个整数 A1,A2,⋅⋅⋅AN。 输出格式 输出一个整数代表答案。 数据范围 1 ≤N≤105 ,−105 ≤Ai≤105 输入样例: 7 1 6 5 4 3 2 1 输出样例: 2
思路:(比较简单)
双指针算法。时间复杂度:O(n)。
把每个数遍历一次,所以是O(n)。
对层数进行循环,分别求权值之和,更新最大值。
注意爆int。
满二叉树的深度为log(1e5) 最多可以有 1 << (log(1e5)) - 1个元素 大概是2^15 ~ 2^16 ,再乘以一个 1e5 所以就爆了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std ;typedef long long LL;const int N = 1e5 +10 ;const int INF = 0x3f3f3f3f ;int n;int t[N];int main () { scanf ("%d" ,&n); for (int i = 1 ;i <= n;i++) scanf ("%d" ,&t[i]); LL max = -INF; int depth = 0 ; for (int i = 1 , d = 1 ;i <= n;i *= 2 ,d++){ LL s = 0 ; for (int j = i;j < i + (1 << d-1 ) && j <= n;j++) s += t[j]; if (s > max){ max = s; depth = d; } } printf ("%d\n" ,depth); return 0 ; }
4.2 acwing.1096. 地牢大师 《信息学奥赛一本通》 , POJ 2251
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 你现在被困在一个三维地牢中,需要找到最快脱离的出路! 地牢由若干个单位立方体组成,其中部分不含岩石障碍可以直接通过,部分包含岩石障碍无法通过。 向北,向南,向东,向西,向上或向下移动一个单元距离均需要一分钟。 你不能沿对角线移动,迷宫边界都是坚硬的岩石,你不能走出边界范围。 请问,你有可能逃脱吗? 如果可以,需要多长时间? 输入格式 输入包含多组测试数据。 每组数据第一行包含三个整数 L,R,C 分别表示地牢层数,以及每一层地牢的行数和列数。 接下来是 L 个 R 行 C 列的字符矩阵,用来表示每一层地牢的具体状况。 每个字符用来描述一个地牢单元的具体状况。 其中, 充满岩石障碍的单元格用”#”表示,不含障碍的空单元格用”.”表示,你的起始位置用”S”表示,终点用”E”表示。 每一个字符矩阵后面都会包含一个空行。 当输入一行为”0 0 0 ”时,表示输入终止。 输出格式 每组数据输出一个结果,每个结果占一行。 如果能够逃脱地牢,则输出”Escaped in x minute(s).”,其中X为逃脱所需最短时间。 如果不能逃脱地牢,则输出”Trapped!”。 数据范围 1 ≤L,R,C≤100 输入样例: 3 4 5 S.... .###. .##.. ###.# ##### ##### ##.## ##... ##### ##### #.### ####E 1 3 3 S## #E# ### 0 0 0 输出样例: Escaped in 11 minute(s). Trapped!
思路:
这是一个三维的迷宫问题。
根据数据范围:迷宫最多是10^6,所以时间复杂度应当控制为:O(n)。
做法:二维BFS扩展成三维BFS。
二维与三维坐标偏移对比:
代码:队列,队尾入队,队头出队。
本题用数组实现BFS,用队列queue也行,效率更低一点。可以当作模板记忆了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std ;const int N = 101 ;struct Point { int x,y,z; }; int dx[] = {1 ,-1 ,0 ,0 ,0 ,0 };int dy[] = {0 ,0 ,1 ,-1 ,0 ,0 };int dz[] = {0 ,0 ,0 ,0 ,1 ,-1 };int L,R,C;char g[N][N][N];int dist[N][N][N];Point q[N*N*N]; int bfs (Point S,Point E) { int hh = 0 ,tt = 0 ; q[0 ] = S; memset (dist,-1 ,sizeof dist); dist[S.x][S.y][S.z] = 0 ; while (hh <= tt){ auto t = q[hh++]; for (int i = 0 ;i < 6 ;i++){ int x = t.x + dx[i],y = t.y + dy[i],z = t.z + dz[i]; if ( x < 0 || x >= L || y < 0 || y >= R || z < 0 || z >= C) continue ; if (dist[x][y][z] != -1 ) continue ; if (g[x][y][z] == '#' ) continue ; dist[x][y][z] = dist[t.x][t.y][t.z] + 1 ; if (g[x][y][z] == 'E' ) return dist[x][y][z]; q[++tt] = {x,y,z}; } } return -1 ; } int main () { Point start,end; while (scanf ("%d %d %d" ,&L,&R,&C),L && R && C){ for (int i = 0 ;i < L;i++) for (int j = 0 ;j < R;j++){ scanf ("%s" ,g[i][j]); for (int k = 0 ;k < C;k++){ if (g[i][j][k] == 'S' ) start = {i,j,k}; } } int res = bfs(start,end); if (res == -1 ) puts ("Trapped!" ); else printf ("Escaped in %d minute(s).\n" ,res); } return 0 ; }
4.3 acwing.1233. 全球变暖 第九届蓝桥杯省赛C++A/B组,第九届蓝桥杯省赛JAVAA/B组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 你有一张某海域 N×N 像素的照片,”.”表示海洋、”#”表示陆地,如下所示: ....... .##.... .##.... ....##. ..####. ...###. ....... 其中”上下左右”四个方向上连在一起的一片陆地组成一座岛屿,例如上图就有 2 座岛屿。 由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。 具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。 例如上图中的海域未来会变成如下样子: ....... ....... ....... ....... ....#.. ....... ....... 请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。 输入格式 第一行包含一个整数N。 以下 N 行 N 列,包含一个由字符”#”和”.”构成的 N×N 字符矩阵,代表一张海域照片,”#”表示陆地,”.”表示海洋。 照片保证第 1 行、第 1 列、第 N 行、第 N 列的像素都是海洋。 输出格式 一个整数表示答案。 数据范围 1 ≤N≤1000 输入样例1 : 7 ....... .##.... .##.... ....##. ..####. ...###. ....... 输出样例1 : 1 输入样例2 : 9 ......... .##.##... .#####... .##.##... ......... .##.#.... .#.###... .#..#.... ......... 输出样例2 : 1
思路:
这题也是考察Flood Fill(洪水灌溉)算法。
根据数据范围推断时间复杂度要控制为O(n)。
十九讲的红与黑求的是一个连通块的大小,而这题求的是连通块的个数,有多个。
先统计一共有多少连通块,再计算被淹没的连通块有多少个。
如何判断岛屿是否被淹没?
我们可以开两个变量total和bound,分别表示总像素个数和边界像素个数,如果total == bound
,说明淹
没。
total怎么算?每拓展一个像素,total+1;
bound怎么算?拓展的像素四个方向有海,bound+1.
代码1:BFS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #include <bits/stdc++.h> using namespace std ;#define x first #define y second typedef pair <int ,int > PII;const int N = 1e3 +5 ;char g[N][N];PII q[N*N]; bool st[N][N];int n;int dx[] = {1 ,-1 ,0 ,0 },dy[] = {0 ,0 ,1 ,-1 };void bfs (int x,int y,int &total,int &bound) { int hh = 0 ,tt = 0 ; q[0 ] = {x,y}; st[x][y] = true ; while (hh <= tt){ auto t = q[hh++]; total++; bool is_bound = false ; for (int i = 0 ;i < 4 ;i++){ int a = t.x + dx[i],b = t.y + dy[i]; if (a < 0 || a >= n || b < 0 || b >= n) continue ; if (st[a][b]) continue ; if (g[a][b] == '.' ){ is_bound = true ; continue ; } q[++tt] = {a,b}; st[a][b] = true ; } if (is_bound) bound++; } } int main () { scanf ("%d" ,&n); for (int i = 0 ;i < n;i++) scanf ("%s" ,g[i]); int cnt = 0 ; for (int i = 0 ;i < n;i++) for (int j = 0 ;j < n;j++){ if (!st[i][j] && g[i][j] == '#' ){ int total = 0 ,bound = 0 ; bfs(i,j,total,bound); if (bound == total) cnt++; } } printf ("%d\n" ,cnt); return 0 ; }
代码2:DFS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <bits/stdc++.h> using namespace std ;int n;char a[1010 ][1010 ]; int vis[1010 ][1010 ]={0 }; int d[4 ][2 ] = {{0 ,1 }, {0 ,-1 }, {1 ,0 }, {-1 ,0 }}; int flag; void dfs (int x, int y) { vis[x][y] = 1 ; if (a[x][y+1 ]=='#' && a[x][y-1 ]=='#' && a[x+1 ][y]=='#' && a[x-1 ][y]=='#' ) flag = 1 ; for (int i = 0 ; i < 4 ; i++){ int nx = x + d[i][0 ], ny = y + d[i][1 ]; if (vis[nx][ny]==0 && a[nx][ny]=='#' ) dfs(nx,ny); } } int main () { cin >> n; for (int i = 1 ; i <= n; i++) for (int j = 1 ; j <= n; j++) cin >> a[i][j]; int ans = 0 ; for (int i = 1 ; i <= n; i++) for (int j = 1 ; j <= n; j++) if (a[i][j]=='#' && vis[i][j]==0 ){ flag = 0 ; dfs(i,j); if (flag == 0 ) ans++; } cout <<ans<<endl ; return 0 ; } 作者:Ooooooooooops 链接:https: 来源:AcWing 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
DFS:地图从1开始计算,外面多了一圈,就不用单独处理越界情况。