[洛谷刷题8]

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 10001n10001≤m≤10001 \leq m \leq 10001m1000

解题思路

问题分析

题目要求计算敌国地图上可以投放伞兵的点的数量。伞兵在有风的区域会被风不断刮动,直到进入无风区(标记为o)。因此,可以投放伞兵的点是那些可以通过风的引导最终到达无风区的点。

解决方案

广度优先搜索(BFS)

  • BFS 适用于从多个起点开始的层次遍历,能有效找到所有可达的节点。
  • 将所有无风区(o)作为起点,放入队列中。
  • 从这些起点开始,按照风的方向访问相邻的节点,标记可以到达的节点。
  • 最终统计所有被标记的节点数量,即为可以投放伞兵的点的数量。

深度优先搜索(DFS)

  • DFS 从每个无风区(o)出发,递归访问所有可以通过风的引导到达的节点。
  • 对于每个无风区,使用 DFS 遍历所有可达的节点,并标记这些节点。
  • 最终统计所有被标记的节点数量。

BFS 实现思路

  1. 初始化

    • 读取地图的大小 nm
    • 使用一个队列存储所有无风区的坐标。
    • 初始化访问标记数组 vis,标记所有无风区为已访问。
  2. BFS 遍历

    • 从队列中取出一个节点,统计为可投放点。
    • 根据当前节点的风向,访问相邻的节点:
      • 如果风向为 u,则向下移动(行加1)。
      • 如果风向为 d,则向上移动(行减1)。
      • 如果风向为 l,则向右移动(列加1)。
      • 如果风向为 r,则向左移动(列减1)。
    • 将相邻的未访问节点加入队列,并标记为已访问。
  3. 统计结果

    • 遍历所有节点,统计被标记的节点数量。

DFS 实现思路

  1. 初始化

    • 读取地图的大小 nm
    • 初始化访问标记数组 vis
  2. DFS 遍历

    • 对于每个无风区(o),调用 DFS 函数。
    • 在 DFS 函数中,标记当前节点为已访问。
    • 根据当前节点的风向,递归访问相邻的节点:
      • 如果风向为 u,则向下移动(行加1)。
      • 如果风向为 d,则向上移动(行减1)。
      • 如果风向为 l,则向右移动(列加1)。
      • 如果风向为 r,则向左移动(列减1)。
    • 确保递归调用时节点在地图范围内且未被访问。
  3. 统计结果

    • 遍历所有节点,统计被标记的节点数量。
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

题目大意

女孩给出 LLLRRR 两个数,求 [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-11

解释一下:
加的 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Genius_Qymm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值