今天的刷题刷的是双指针跟BFS,其中包括了图的BFS,以及怎么去建图的问题,还是慢慢练,慢慢就熟悉了,然后还有一些竞赛中要用到的数学函数还是得记记多多积累!
标签:双指针算法
思路:
就是规定一个起点,然后再走固定的个数,再一判断就行了,再把个数左移一位
题目描述:
给定一棵包含 N 个节点的完全二叉树,树上每个节点都有一个权值,按从上到下、从左到右的顺序依次是 A1,A2,⋅⋅⋅AN,如下图所示:
现在小明要把相同深度的节点的权值加在一起,他想知道哪个深度的节点权值之和最大?
如果有多个深度的权值和同为最大,请你输出其中最小的深度。
注:根的深度是 1。
输入格式
第一行包含一个整数 N。
第二行包含 N
个整数 A1,A2,⋅⋅⋅AN。
输出格式
输出一个整数代表答案。
数据范围
1≤N≤105,−105≤Ai≤105
输入样例:
7
1 6 5 4 3 2 1
输出样例:
2
示例代码:
#include
#include
#include
using namespace std;
typedef long long LL;
const int N = 1e5+10;
int a[N];
int n;
int main()
{
scanf("%d", &n);
for(int i = 0; i < n; ++i) scanf("%d", &a[i]);
LL res = -1e18;
int id = 0;
for(int i = 0, j = 1; i < n;)
{
LL step = 0;
int t = i;
while(i < t + j && i < n) //完全二叉树 i可能会越界
{
step += a[i];
i++;
}
//cout << step << endl;
if(step > res)
{
res = step;
id = log2(j);
}
j <<= 1;
}
//cout << res << endl;
cout << id+1 << endl;
return 0;
}
标签:BFS
思路:
就是一个BFS模板,然后区别是三维的,其实只不过方向多了两,其余都差不多
题目描述:
你现在被困在一个三维地牢中,需要找到最快脱离的出路!
地牢由若干个单位立方体组成,其中部分不含岩石障碍可以直接通过,部分包含岩石障碍无法通过。
向北,向南,向东,向西,向上或向下移动一个单元距离均需要一分钟。
你不能沿对角线移动,迷宫边界都是坚硬的岩石,你不能走出边界范围。
请问,你有可能逃脱吗?
如果可以,需要多长时间?
输入格式
输入包含多组测试数据。
每组数据第一行包含三个整数 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!
示例代码:
#include
#include
#include
#include
using namespace std;
const int N = 110;
struct Node
{
int x,y,z;
};
int l,r,c;
char g[N][N][N];
int dist[N][N][N];
Node S, E;
Node q[N*N*N];
int dir[6][3] = {0,0,1, 0,0,-1, 0,1,0, 0,-1,0, 1,0,0, -1,0,0};
int bfs()
{
memset(dist, -1, sizeof dist);
dist[S.x][S.y][S.z] = 0;
int hh = 0, tt = -1;
q[++tt] = {S.x,S.y,S.z};
while(hh <= tt)
{
auto t = q[hh++];
for(int i = 0; i < 6; ++i)
{
int x = t.x + dir[i][0];
int y = t.y + dir[i][1];
int z = t.z + dir[i][2];
if(x < 0 || x >= l || y < 0 || y >= r || z < 0 || z >= c) continue;
if(dist[x][y][z] != -1 || g[x][y][z] == '#') continue;
dist[x][y][z] = dist[t.x][t.y][t.z] + 1;
q[++tt] = {x,y,z};
if(g[x][y][z] == 'E') return dist[x][y][z];
}
}
return -1;
}
int main()
{
while(1)
{
scanf("%d%d%d", &l, &r, &c);
if(l == 0 || r == 0 || c == 0) break;
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') S = {i,j,k};
if(g[i][j][k] == 'E') E = {i,j,k};
}
}
}
int t = bfs();
if(t == -1) puts("Trapped!");
else printf("Escaped in %d minute(s).\n", t);
}
return 0;
}
标签:BFS
思路:
一种是先把岛屿标记一下,然后遍历每个岛屿,如果这个岛屿中存在一个点四个方向都为’#',那么res++。第二种就是BFS的时候计算点的数量,以及淹没后点的数量,如果相等说明完全淹没。
题目描述:
你有一张某海域 N×N 像素的照片,”.”表示海洋、”#”表示陆地,如下所示:
.......
.##....
.##....
....##.
..####.
...###.
.......
其中”上下左右”四个方向上连在一起的一片陆地组成一座岛屿,例如上图就有 2 座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。
具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
.......
.......
.......
.......
....#..
.......
.......
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
输入格式
第一行包含一个整数N。
以下 N 行 N 列,包含一个由字符”#”和”.”构成的 N×N 字符矩阵,代表一张海域照片,”#”表示陆地,”.”表示海洋。
照片保证第 1 行、第 1 列、第 N 行、第 N 列的像素都是海洋。
输出格式
一个整数表示答案。
数据范围
1≤N≤1000
输入样例1:
7
.......
.##....
.##....
....##.
..####.
...###.
.......
输出样例1:
1
输入样例2:
9
.........
.##.##...
.#####...
.##.##...
.........
.##.#....
.#.###...
.#..#....
.........
输出样例2:
1
示例代码:
思路一:
先把岛屿找出来,然后遍历岛屿,看岛屿中是否存在一个点上下左右都是#
#include
#include
#include
#define x first
#define y second
using namespace std;
const int N = 1010;
typedef pair<int,int> PII;
int n;
char g[N][N];
bool st[N][N], backup[N][N];
PII q[N*N];
int dir[4][2] = {0,1,0,-1,1,0,-1,0};
bool bfs1(int sx, int sy)
{
st[sx][sy] = true;
int hh = 0, tt = -1;
q[++tt] = {sx,sy};
while(hh <= tt)
{
auto t = q[hh++];
for(int i = 0; i < 4; ++i)
{
int x = t.x + dir[i][0];
int y = t.y + dir[i][1];
if(x < 0 || x >= n || y < 0 || y >= n) continue;
if(st[x][y] || g[x][y] == '.') continue;
st[x][y] = true;
q[++tt] = {x,y};
}
}
return true;
}
bool bfs2(int sx, int sy)
{
//memcpy(backup, st, sizeof st);
bool flag = true;
st[sx][sy] = false;
int hh = 0, tt = -1;
q[++tt] = {sx,sy};
while(hh <= tt)
{
auto t = q[hh++];
for(int i = 0; i < 4; ++i)
{
int x = t.x + dir[i][0];
int y = t.y + dir[i][1];
if(x < 0 || x >= n || y < 0 || y >= n) continue;
if(!st[x][y]) continue;
if(g[x][y] == '.') continue;
if(g[x-1][y] == '#' && g[x+1][y] == '#' && g[x][y-1] == '#' && g[x][y+1] == '#') flag = false;;
st[x][y] = false;
q[++tt] = {x,y};
}
}
// memcpy(st,backup, sizeof st);
return flag;
}
int main()
{
scanf("%d", &n);
for(int i = 0; i < n; ++i) scanf("%s", g[i]);
int res1 = 0, res2 = 0; // 代表岛屿数量
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
if(g[i][j] == '#' && !st[i][j])
{
bool t = bfs1(i,j);
res1++;
}
}
}
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
if(st[i][j])
{
if(bfs2(i,j))
{
res2++;
}
}
}
}
//cout << res1 << " " << res2 << endl;
cout << res2 << endl;
return 0;
}
思路二:
通过BFS判断每个岛屿中的岛屿数顺便判断海洋数
#include
#include
#include
using namespace std;
typedef pair<int,int> PII;
#define x first
#define y second
const int N = 1010;
int n;
char g[N][N];
bool st[N][N];
PII q[N*N];
int dir[4][2] = {0,1,0,-1,1,0,-1,0};
bool bfs(PII start)
{
st[start.x][start.y] = true;
int total = 1, sea = 0;
int hh = 0, tt = -1;
q[++tt] = {start.x,start.y};
while(hh <= tt)
{
auto t = q[hh++];
bool flag = false;
for(int i = 0; i < 4; ++i)
{
int x = t.x + dir[i][0];
int y = t.y + dir[i][1];
if(x < 0 || x >= n || y < 0 || y >= n) continue;
if(st[x][y]) continue;
if(g[x][y] == '.') {flag = true; continue;}
st[x][y] = true;
total++;
q[++tt] = {x,y};
}
if(flag) sea++;
}
//cout << sea << " " << total << endl;
if(sea == total) return true;
else return false;
}
int main()
{
scanf("%d", &n);
for(int i = 0; i < n; ++i) scanf("%s", g[i]);
int res = 0;
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
if(!st[i][j] && g[i][j] == '#')
{
if(bfs({i,j})) res++;
}
}
}
printf("%d\n", res);
return 0;
}
标签:树的直径,BFS
思路:
本题其实就是求树的直径:任取一点x,BFS一下,找距离最远的点,然后再从这个点为起点,再遍历一次,这时最远的距离就是树的直径了
题目描述:
很久以前,T 王国空前繁荣。
为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。
为节省经费,T 国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。
同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。
J 是 T 国重要大臣,他巡查于各大城市之间,体察民情。
所以,从一个城市马不停蹄地到另一个城市成了 J 最常做的事情。
他有一个钱袋,用于存放往来城市间的路费。
聪明的 J 发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关。
具体来说,一段连续的旅途里,第 1 千米的花费为 11,第 2 千米的花费为 12,第 3 千米的花费为 13,…,第 x 千米的花费为 x+10。
也就是说,如果一段旅途的总长度为 1 千米,则刚好需要花费 11,如果一段旅途的总长度为 2 千米,则第 1 千米花费 11,
第 2 千米花费 12,一共需要花费 11+12=23。
J 大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?
输入格式
输入的第一行包含一个整数 n,表示包括首都在内的 T 王国的城市数。
城市从 1 开始依次编号,1 号城市为首都。
接下来 n−1 行,描述 T 国的高速路(T 国的高速路一定是 n−1 条)。
每行三个整数 Pi,Qi,Di,表示城市 Pi 和城市 Qi 之间有一条双向高速路,长度为 Di 千米。
输出格式
输出一个整数,表示大臣 J 最多花费的路费是多少。
数据范围
1≤n≤105,1≤Pi,Qi≤n,1≤Di≤1000
输入样例:
5
1 2 2
1 3 1
2 4 5
2 5 4
输出样例:
135
示例代码:
#include
#include
#include
using namespace std;
typedef long long LL;
const int N = 1e5+10, M = N * 2;
int h[N], e[M], w[M], ne[M], idx;
int n;
LL dist[N]; //到i号点的距离
int q[N];
LL maxid, maxs = -1e18;
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
void bfs(int start)
{
memset(dist, -1, sizeof dist);
dist[start] = 0;
int hh = 0, tt = -1;
q[++tt] = start;
while(hh <= tt)
{
auto t = q[hh++];
for(int i = h[t]; i != -1; i = ne[i])
{
int j = e[i];
if(dist[j] != -1) continue;
dist[j] = dist[t] + w[i];
q[++tt] = j;
if(dist[j] > maxs) {maxs = dist[j], maxid = j;}
}
}
}
int main()
{
memset(h, -1, sizeof h);
scanf("%d", &n);
for(int i = 0; i < n; ++i)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a,b,c);
add(b,a,c);
}
bfs(1);
maxs = -1e18;
bfs(maxid);
LL res = maxs * 10 + maxs*(maxs+1)/2;
printf("%lld\n", res);
return 0;
}