NC13224 送外卖
题目
题目描述
n 个小区排成一列,编号为从 0 到 n-1 。一开始,美团外卖员在第0号小区,目标为位于第 n-1 个小区的配送站。
给定两个整数数列 a[0]~a[n-1] 和 b[0]~b[n-1] ,在每个小区 i 里你有两种选择:
- 选择a:向前 a[i] 个小区。
- 选择b:向前 b[i] 个小区。
把每步的选择写成一个关于字符 ‘a’ 和 ‘b’ 的字符串。求到达小区n-1的方案中,字典序最小的字符串。如果做出某个选择时,你跳出了这n个小区的范围,则这个选择不合法。
• 当没有合法的选择序列时,输出 “No solution!”。
• 当字典序最小的字符串无限长时,输出 “Infinity!”。
• 否则,输出这个选择字符串。
字典序定义如下:串s和串t,如果串 s 字典序比串 t 小,则
• 存在整数 i ≥ -1,使得∀j,0 ≤ j ≤ i,满足s[j] = t[j] 且 s[i+1] < t[i+1]。
• 其中,空字符 < ‘a’ < ‘b’。
输入描述
输入有 3 行。
第一行输入一个整数 n (1 ≤ n ≤ 10^5)。
第二行输入 n 个整数,分别表示 a[i] 。
第三行输入 n 个整数,分别表示 b[i] 。
−n ≤ a[i], b[i] ≤ n
输出描述
输出一行字符串表示答案。
示例1
输入
7
5 -3 6 5 -5 -1 6
-6 1 4 -2 0 -2 0
输出
abbbb
题解
知识点:DFS。
这道题难点在于字典序最小以及字典序最小情况下是否是无穷的。
首先字典序最小因此每步都要选择最小的字母和步数无关,这样用dfs最合适,因为dfs每次都可以选择一个最小的继续,这样一定是从字典序最小的开始遍历。
因为直到路径上可能出现环路,因此在搜索过程中把出现环路的点标记并跳出。
最后搜索到合法的路径后回溯记录答案,如果路径中存在被标记为环路的点(一定比这条有限路径字典序小)则说明有字典序更小的无限路径,则标记一下最后输出的时候直接输出无限,否则输出回溯记录的答案,如果到所有路径都遍历完没有答案则输出无解。
时间复杂度 \(O(?)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
using namespace std;
int n, a[100007], b[100007];
bool vis[100007], inf[100007], flag;
char ans[100007];
bool dfs(int x = 0, int step = 0) {
if (x < 0 || x >= n) return false;
if (vis[x]) {
inf[x] = 1;///标记环路点,并且因为是深搜,所以环路点若可以在路径中出现,则字典序一定是比有限的小
return false;///这个点不搜索了
}
if (x == n - 1) {
ans[step] = '\0';///终止符
return true;
}
vis[x] = 1;///标记访问点
///选a或b
if (dfs(x + a[x], step + 1)) {///找到就回溯
ans[step] = 'a';
if (inf[x]) flag = 1;///该点是否在出现小字典序的环路
return true;
}
if (dfs(x + b[x], step + 1)) {
ans[step] = 'b';
if (inf[x]) flag = 1;
return true;
}
return false;///两条路都没有,那么这个点是错的
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 0;i < n;i++) cin >> a[i];
for (int i = 0;i < n;i++) cin >> b[i];
if (dfs()) {
if (flag) cout << "Infinity!" << '\n';///无穷是要在已经是最短路径的情况下是环路才行,而不是随便一条环路都行
else cout << ans << '\n';
}
else cout << "No solution!" << '\n';
return 0;
}
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16483113.html