牛客网:S老师的签到 ← BFS

该篇文章讲述了在给定字符矩阵中寻找从左上角到右下角字典序最小路径的算法,结合了动态规划和广度优先搜索,以及位异或操作在代码中的应用。
摘要由CSDN通过智能技术生成

【题目来源】
https://ac.nowcoder.com/acm/contest/76652/B

【题目描述】
S 老师擅长 OI,他给你了这样一道签到题:
给定一个 n×m 的小写字母构成的字符矩阵 c,从左上角 (1,1) 走到右下角 (n,m),只能向下或向右,求经过的格子形成的字符串字典序最小的方案。
你觉得很简单,决定立刻 AC。

【输入格式】
第一行包含两个整数 n,m(1≤n,m≤
2^10),表示矩阵的行数和列数。
接下来的 n 行,第 i 行包含长度为 m 的字符串,表示 c(i,1),c(i,2),⋯,c(i,m)。

【输出格式】
一行,一个字符串,表示答案。

【输入样例】
2 3
abc
bza

【输出样例】
abca

【样例说明】
有 abca, abza 两种不同的路径,其中 abca 字典序最小。

【算法分析】

本题是典型的动态规划题目,可按照最后一步法进行分析
最后一步法:https://blog.csdn.net/hnjzsyjyj/article/details/112797538
● 当然,本题可以使用广度优先搜索(BFS)进行求解。此题用 BFS 比用 DP 的代码复杂。根据题意的要求,可以发现从左上角到右下角形成的路径一定是 n+m−1 个字符(n, m 表示矩阵的行数和列数)。而 BFS 有“分层”的核心思想,故在本题中以 x+y 相同的值作为“分层”的依据。即若从某位置开始,则位于同一层的是 x+y 的值相同的位置。其中,x 是向下走的距离,y 是向右走的距离。
● 运算符
^ 表示按位异或
https://blog.csdn.net/hnjzsyjyj/article/details/138260926
若 n=0,则 n^0=00000000 ^ 00000000=0,n^1=00000000 ^ 00000001=1。
若 n=1,则 n^0=00000001 ^ 00000000=1,n^1=00000001 ^ 00000001=0。

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cin>>n;

    cout<<n<<"^0="<<(n^0)<<endl;
    cout<<n<<"^1="<<(n^1)<<endl;

    return 0;
}

/*
in:
1
out:
1^0=1
1^1=0
------
in:
0
out:
0^0=0
0^1=1
*/

● C++11 标准中的 for 循环,用 auto 以简洁、统一的方式来遍历容器和数组。
https://blog.csdn.net/hnjzsyjyj/article/details/138260383

#include <bits/stdc++.h>
using namespace std;

vector<int> v;

int main() {
    int n;
    cin>>n;
    for(int i=1; i<=n; i++) v.push_back(i);

    for(auto val:v) {
        cout<<val<<" "; //1 2 3 4 5
    }
    cout<<endl;

    for(auto &val:v) {
        cout<<++val<<" "; //2 3 4 5 6
    }
    cout<<endl;

    return 0;
}

/*
in:
5

out:
1 2 3 4 5
2 3 4 5 6
*/


【算法代码】

#include <bits/stdc++.h>
using namespace std;

const int maxn=1025; //2^10=1024
char g[maxn][maxn];
int st[maxn][maxn];
char ans[maxn*2];
int n,m;

void bfs() {
    vector<pair<int,int>> q[2];
    int k=0;
    ans[k]=g[1][1];
    st[1][1]=1;
    
    int id=0;
    q[id].push_back({1,1});

    for(int i=1; i<=n+m-2; i++) {
        id^=1; //^表示按位异或
        q[id].clear();
        char s='z';
        for(auto &t:q[id^1]) {
            int x=t.first,y=t.second;
            if(x<n) s=min(s,g[x+1][y]);
            if(y<m) s=min(s,g[x][y+1]);
        }

        ans[++k]=s;

        for(auto &t:q[id^1]) {
            int x=t.first,y=t.second;
            if(x<n && g[x+1][y]==s && !st[x+1][y]) {
                st[x+1][y]=1;
                q[id].push_back({x+1,y});
            }

            if(y<m && g[x][y+1]==s && !st[x][y+1]) {
                st[x][y+1]=1;
                q[id].push_back({x,y+1});
            }
        }
    }
}

int main() {
    cin>>n>>m;
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=m; j++) {
            cin>>g[i][j];
        }
    }

    bfs();

    cout<<ans;

    return 0;
}


/*
in:
2 3
abc
bza

out:
abca
*/




【参考文献】
https://blog.csdn.net/weixin_38346042/article/details/131599408
https://blog.csdn.net/2303_79132118/article/details/137865719
https://blog.csdn.net/2303_76151267/article/details/136766539
https://www.acwing.com/problem/content/1020/
https://zhuanlan.zhihu.com/p/688110355
https://blog.csdn.net/qq_63432403/article/details/136752377
https://www.nowcoder.com/discuss/598273560788951040







 

  • 37
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值