题意:如果一个字符串包含两个相邻的重复子串,则称它是“容易的串”,其他串称为“困难的串”。例如,BB、ABCDACABCAB、ABCDABCD都是容易的串,而D、DC、ABDAB、CBABCBA都是困难的串。输入正整数n和L,输出由前L个字符组成的、字典序第n小的困难的串。例如,当L = 3时,前7个困难的串分别为A、AB、ABA、ABAC、ABACA、ABACAB、ABACABA。输入保证答案不超过80个字符。(本段摘自《算法竞赛入门经典(第2版)》
分析:逐个枚举当前位置可能的字符,去判断是否满足题意,如果满足则递归处理下一位,如果当前位置枚举完仍然没有到达第n个,则进行回溯,返回上一层继续枚举,直到找到第n个即可。
代码:
#include <fstream>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <stack>
#include <sstream>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <vector>
#include <set>
#include <string>
#include <vector>
using namespace std;
const int maxn = 80 + 5;
int n, l, cnt, deep;
bool flag;
char a[maxn];
bool judge()
{
bool f;
for (int i = 1; i <= cnt / 2; ++i)
{
f = true;
for (int j = 0; j < i; ++j)
if (a[cnt - j - 1] != a[cnt - j - 1 - i])
{
f = false;
break;
}
if (f)
return false;
}
return true;
}
void DFS()
{
if (deep == n)
{
flag = true;
return;
}
for (int i = 0; i < l; ++i)
{
a[cnt++] = i + 'A';
if (judge())
{
++deep;
DFS();
if (flag)
return;
}
--cnt;
}
}
int main()
{
while (~scanf("%d%d", &n, &l), n || l)
{
cnt = 0;
deep = 0;
flag = false;
DFS();
for (int i = 0; i < cnt; ++i)
{
printf("%c", a[i]);
if (i == cnt - 1 || i == 63)
printf("\n");
else if ((i + 1) % 4 == 0)
printf(" ");
}
printf("%d\n", cnt);
}
return 0;
}