问题描述:如果一个字符串包含两个相邻的重复子串,则称它为容易的串,其他串称为困难的串,如:BB,ABCDACABCAB,ABCDABCD都是容易的,D,DC,ABDAB,CBABCBA都是困难的。
输入正整数n,L,输出由前L个字符组成的,字典序第n小的困难的串。例如,当L=3时,前7个困难的串分别为:A,AB,ABA,ABAC,ABACA,ABACAB,ABACABA
思路:如果没加入一个字符,就考虑这个这整个字符中的所有字串是不是有重复的,就太浪费时间了,因为有大量的重复工作。其实只需要考虑加入的这个字符所组成的字串和该子串前面的相同长度的子串是不是相同就行了。而加入的这个字符所组成的子串就叫做后缀,也就是由该字符结尾的字符串。
#include<stdio.h>
#include<iostream>
using namespace std;
const int maxn = 105;
int L,n,S[maxn],cnt;
int dfs(int cur)
{
if(cnt++ == n){
for(int i = 0;i < cur;i++){
printf("%c",'A' + S[i]);
}
printf("\n");
return 0;
}
for(int i = 0;i < L;i++){
int ok = 1;
S[cur] = i;
int l = cur % 2 == 0?cur / 2:cur/2+ 1;
for(int j = 1;j <= l;j++){
int e = 1;
for(int k = 0;k < j;k++){
if(S[cur - k] != S[cur - k - j]){e = 0;break;}
}
if(e){ok = 0;break;}
}
if(ok)if(!dfs(cur + 1))return 0;
}
return 1;
}
int main()
{
while(cin>>n>>L){
cnt = 0;
dfs(0);
}
return 0;
}
这个代码中的j就是以该字符结尾的子串的长度,因为只要大于一半就不需要在比较了,肯定不会有重复的所以,就是cur / 2的上取整。而下面的代码是从1开始的,因此是下取整。
#include<stdio.h>
#include<iostream>
using namespace std;
int L,n,cnt;
const int maxn = 100 + 5;
int S[maxn];
int dfs(int cur)
{
if(cnt++ == n){
for(int i = 1;i < cur;i++){printf("%c",'A' + S[i]);}
printf("\n");
return 0;
}
for(int i = 0;i < L;i++){
S[cur] = i;
int ok = 1;
for(int j = 1;j <= cur / 2 ;j++){
int e = 1;
for(int k = 0;k < j;k++)
if(S[cur - k] != S[cur - k - j]){e = 0;break;}
if(e){ok = 0;break;}
}
if(ok)if(!dfs(cur + 1))return 0;
}
return 1;
}
int main()
{
cin>>n>>L;
c
n = 0;
dfs(1);
}