紫书刷题进行中,题解系列【GitHub|CSDN】
例题7-5 UVA129 Krypton Factor(38行AC代码)
题目大意
用26个大写字母[A,Z]的前L个字母,构造无重复连续子串的字符串,按照字典序排序后,输出第n个字符串
思路分析
本题枚举可重复使用每个元素,若每次都是从小到大的顺序枚举字母,那么就是按字典序升序排列找到的结果,关键在于如何判断无重复连续子串?
如果按照输入样例绘制解答树,会发现,hard字符串是类似增量构造,每次只需从尾部向前判断是否存在重复连续子串即可
详细实现见代码注释
AC代码(C++11,相邻子串剪枝)
#include<bits/stdc++.h>
using namespace std;
int n, L;
vector<int> ans; // 存储答案
bool isHard(int val) { // 判断加入val后是否为Hard
ans.push_back(val); // 先加入,最后发现不是hard在弹出
for (int len=1; len <= ans.size()/2; len++) { // 遍历所有子串长度
bool isSame=true;
for (int j=0; j < len; j ++) { // 遍历相邻子串,判断是否相同
if (ans[ans.size()-len+j] != ans[ans.size()-2*len+j]) {isSame=false; break;}
}
if (isSame) {ans.pop_back(); return false;} // 找到两个相同子串
}
return true;
}
void dfs(int& num) { // 递归搜索,num: 已找到hard的个数
if (num == n) { // 输出
for (int i=0; i < ans.size(); i ++) {
printf("%c", ans[i]-1+'A');
if ((i+1)%64 == 0 || i+1 == ans.size()) puts("");
else if ((i+1)%4 == 0) putchar(' ');
}
printf("%d\n", ans.size());
return; // 直接返回
}
for (int i=1; i <= L && num < n; i ++) { // 剪枝: num<n
if (isHard(i)) {
dfs(++num); ans.pop_back(); // 记得弹出无用的元素!!!
}
}
}
int main() {
while (scanf("%d %d", &n, &L) == 2 && n && L) {
ans.clear(); int num=0;
dfs(num);
}
return 0;
}