[洛谷刷题8]
P1913 L国的战斗之伞兵(标准的搜索题 BFS or DFS)
https://www.luogu.com.cn/problem/P1913
题目背景
L 国即将与 I 国发动战争!!
题目描述
为了在敌国渗透作战,指挥官决定:派出伞兵前往敌国!然而敌国的风十分强烈,能让伞兵在同一高度不停转悠,直到被刮到一个无风区……(可怜的小兵)
输入格式
第一行: n , m n,m n,m 两个正整数,表示敌国的大小。
以下 n n n 行,每行 m m m 个字符,u
表示风向北吹;d
表示风向南吹;l
表示风向西吹;r
表示风向东吹;o
表示无风。(上北下南,左西右东)
输出格式
一个数:表示有几个点可以放下伞兵。
输入输出样例 #1
输入 #1
5 5
rrrrr
rdddr
rroll
uuuuu
uuuuu
输出 #1
19
说明/提示
数据范围:
1 ≤ n ≤ 1000 1 \leq n \leq 1000 1≤n≤1000, 1 ≤ m ≤ 1000 1 \leq m \leq 1000 1≤m≤1000。
解题思路
问题分析
题目要求计算敌国地图上可以投放伞兵的点的数量。伞兵在有风的区域会被风不断刮动,直到进入无风区(标记为o
)。因此,可以投放伞兵的点是那些可以通过风的引导最终到达无风区的点。
解决方案
广度优先搜索(BFS)
- BFS 适用于从多个起点开始的层次遍历,能有效找到所有可达的节点。
- 将所有无风区(
o
)作为起点,放入队列中。 - 从这些起点开始,按照风的方向访问相邻的节点,标记可以到达的节点。
- 最终统计所有被标记的节点数量,即为可以投放伞兵的点的数量。
深度优先搜索(DFS)
- DFS 从每个无风区(
o
)出发,递归访问所有可以通过风的引导到达的节点。 - 对于每个无风区,使用 DFS 遍历所有可达的节点,并标记这些节点。
- 最终统计所有被标记的节点数量。
BFS 实现思路
-
初始化:
- 读取地图的大小
n
和m
。 - 使用一个队列存储所有无风区的坐标。
- 初始化访问标记数组
vis
,标记所有无风区为已访问。
- 读取地图的大小
-
BFS 遍历:
- 从队列中取出一个节点,统计为可投放点。
- 根据当前节点的风向,访问相邻的节点:
- 如果风向为
u
,则向下移动(行加1)。 - 如果风向为
d
,则向上移动(行减1)。 - 如果风向为
l
,则向右移动(列加1)。 - 如果风向为
r
,则向左移动(列减1)。
- 如果风向为
- 将相邻的未访问节点加入队列,并标记为已访问。
-
统计结果:
- 遍历所有节点,统计被标记的节点数量。
DFS 实现思路
-
初始化:
- 读取地图的大小
n
和m
。 - 初始化访问标记数组
vis
。
- 读取地图的大小
-
DFS 遍历:
- 对于每个无风区(
o
),调用 DFS 函数。 - 在 DFS 函数中,标记当前节点为已访问。
- 根据当前节点的风向,递归访问相邻的节点:
- 如果风向为
u
,则向下移动(行加1)。 - 如果风向为
d
,则向上移动(行减1)。 - 如果风向为
l
,则向右移动(列加1)。 - 如果风向为
r
,则向左移动(列减1)。
- 如果风向为
- 确保递归调用时节点在地图范围内且未被访问。
- 对于每个无风区(
-
统计结果:
- 遍历所有节点,统计被标记的节点数量。
AC Code(BFS)
#include <bits/stdc++.h>
using namespace std;const int N = 1e3+9;
char mp[N][N];
bool vis[N][N];
int ans = 0;void solve(){int n,m;cin >> n >> m;queue<array<int,2>> q;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin >> mp[i][j];if(mp[i][j]=='o'){q.push({i,j});vis[i][j] = true;}}}//lambda函数auto bfs = [&]()->void{while(!q.empty()){array<int,2> tmp = q.front();q.pop();ans++;if(mp[tmp[0]+1][tmp[1]]=='u'&&!vis[tmp[0]+1][tmp[1]]){q.push({tmp[0]+1,tmp[1]});vis[tmp[0]+1][tmp[1]]=true;}if(mp[tmp[0]-1][tmp[1]]=='d'&&!vis[tmp[0]-1][tmp[1]]){q.push({tmp[0]-1,tmp[1]});vis[tmp[0]-1][tmp[1]]=true;}if(mp[tmp[0]][tmp[1]-1]=='r'&&!vis[tmp[0]][tmp[1]-1]){q.push({tmp[0],tmp[1]-1});vis[tmp[0]][tmp[1]-1]=true;}if(mp[tmp[0]][tmp[1]+1]=='l'&&!vis[tmp[0]][tmp[1]+1]){q.push({tmp[0],tmp[1]+1});vis[tmp[0]][tmp[1]+1]=true;}}};bfs();cout << ans;
}int main(){ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);int t=1;//cin >> t;while(t--){solve();}return 0;
}
AC Code(DFS)
#include<iostream>
using namespace std;const int N = 1e3+9;
char mp[N][N];
bool vis[N][N];
int ans = 0;void dfs(int i,int j){ vis[i][j]=true;if(mp[i+1][j]=='u'){dfs(i+1,j);}if(mp[i-1][j]=='d'){dfs(i-1,j);}if(mp[i][j+1]=='l'){dfs(i,j+1);}if(mp[i][j-1]=='r'){dfs(i,j-1);}
}void solve(){int n,m;cin >> n >> m;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin >> mp[i][j];}}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(mp[i][j]=='o'){dfs(i,j);}}}for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(vis[i][j]){ans++;}}}cout << ans;
}int main(){ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);int t=1;//cin >> t;while(t--){solve();}return 0;
}
P2110 欢总喊楼记
https://www.luogu.com.cn/problem/P2110
题目描述
诗经有云:
关关雎鸠,在河之洲。窈窕淑女,君子好逑。
又是一个被风吹过的夏天……一日欢总在图书馆中自习,抬起头来,只见一翩跹女子从面前飘过,真是回眸一笑百媚生,六宫粉黛无颜色!一阵诗情涌上欢总心头,他顺手写下那诗句:
啊,你是爱,是暖,是希望,你是人间四月天!
任时光匆匆而过,欢总一直没能忘记那女子。人言单思苦,欢总偏单思。夜夜难入梦,此心淑可知。偶然一次机会,欢总得知了那女孩的信息。一日,欢总终于鼓起了勇气,他向她表白!
那晚的夜色格外美丽,欢总在楼下慷慨激昂,气氛浪漫而感人。女孩有点心动了,但是直接答应是不是有点太不矜持了呢?于是,她想难难欢总,看看他到底有多少诚意。
女孩给出了两个整数 L 和 R,她要欢总数出到底有多少个这样的 X:L <= X <= R,且 X 的最高位与最低位相等(十进制下)。比如,2、101、329873可以是这样的 X,而23、4567就不是。
孩子们,欢总下辈子的幸福生活就靠你们帮忙了!
输入格式
一行,这一行包括两个整数 L 和 R。
输出格式
一行,这一行包括一个整数,即满足所述性质的 X 的个数。
输入输出样例 #1
输入 #1
2 47
输出 #1
12
说明/提示
【数据规模】
50% 1<=L<=R<=10^6
100% 1<=L<=R<=10^18
题目大意
女孩给出 L L L 和 R R R 两个数,求 [ L , R ] [L,R] [L,R] 中 X X X 的个数,而 X X X 必须满足最高位与最低位相等这个条件(十进制下)。
分析
我们可以发现:
如果直接暴力枚举,必然超时(请看数据范围)。
所以,我们可以通过仔细观察发现:题目问的问题只限制最高位与最低位相等,那么这就是此题的突破口。
接着,我们假设已经确定了最高位。
那么此时的最低位只有 1 种可能(因为最高位与最低位相等)。
这就说明,每 10 个数中,只有 1 个符合题目条件的 X X X。
由此得出本题做法(见下)。
具体做法
将 [ L , R ] [L,R] [L,R] 中的数字分成每 10 个 1 组,然后就可以得到: [ 1 , N ] [1,N] [1,N] 中 X X X 的个数为 N ÷ 10 + 9 N\div10+9 N÷10+9。当然,还有特殊情况,比如最低位小于最高位时,应当 − 1 -1 −1。
解释一下:
加的 9 是因为 [ 1 , 9 ] [1,9] [1,9] 这个区间中有 9 个 X X X。
注意事项
AC Code
#include<bits/stdc++.h>
using namespace std;typedef long long ll;ll solve(ll n){if(n<10){return n;}ll sum = n/10+9;ll p = n;while(p > 9){p /= 10;}ll q = n%10;if(q < p){sum--;}return sum;
}
int main(){ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);ll l,r;cin >> l >> r;cout << solve(r) - solve(l-1);return 0;
}