P1913 L国的战斗之伞兵(标准的搜索题 BFS or DFS)
https://www.luogu.com.cn/problem/P1913
题目背景
L 国即将与 I 国发动战争!!
题目描述
为了在敌国渗透作战,指挥官决定:派出伞兵前往敌国!然而敌国的风十分强烈,能让伞兵在同一高度不停转悠,直到被刮到一个无风区……(可怜的小兵)
输入格式
第一行:n,mn,mn,m 两个正整数,表示敌国的大小。
以下 nnn 行,每行 mmm 个字符,u
表示风向北吹;d
表示风向南吹;l
表示风向西吹;r
表示风向东吹;o
表示无风。(上北下南,左西右东)
输出格式
一个数:表示有几个点可以放下伞兵。
输入输出样例 #1
输入 #1
5 5
rrrrr
rdddr
rroll
uuuuu
uuuuu
输出 #1
19
说明/提示
数据范围:
1≤n≤10001 \leq n \leq 10001≤n≤1000,1≤m≤10001 \leq m \leq 10001≤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
题目大意
女孩给出 LLL 和 RRR 两个数,求 [L,R][L,R][L,R] 中 XXX 的个数,而 XXX 必须满足最高位与最低位相等这个条件(十进制下)。
分析
我们可以发现:
如果直接暴力枚举,必然超时(请看数据范围)。
所以,我们可以通过仔细观察发现:题目问的问题只限制最高位与最低位相等,那么这就是此题的突破口。
接着,我们假设已经确定了最高位。
那么此时的最低位只有 1 种可能(因为最高位与最低位相等)。
这就说明,每 10 个数中,只有 1 个符合题目条件的 XXX。
由此得出本题做法(见下)。
具体做法
将 [L,R][L,R][L,R] 中的数字分成每 10 个 1 组,然后就可以得到:[1,N][1,N][1,N] 中 XXX 的个数为 N÷10+9N\div10+9N÷10+9。当然,还有特殊情况,比如最低位小于最高位时,应当 −1-1−1。
解释一下:
加的 9 是因为 [1,9][1,9][1,9] 这个区间中有 9 个 XXX。
注意事项
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;
}