【题目来源】
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