问题描述:如果一个字符串包含两个相邻的重复子串,则称它为容易的串,其他串称为困难的串,如:BB,ABCDACABCAB,ABCDABCD都是容易的,D,DC,ABDAB,CBABCBA都是困难的。
输入正整数n,L,输出由前L个字符组成的,字典序第n小的困难的串。例如,当L=3时,前7个困难的串分别为:A,AB,ABA,ABAC,ABACA,ABACAB,ABACABA
思路很简单:
方法1,检查所有长度为偶数的子串,判断前一半和后一半是否相等,方法可以,但会做 很多重复的事情。
改进:与八皇后问题判断是否冲突的过程类似,判断当前皇后与前面的皇后是否冲突,无需再去判断前面的皇后是否冲突,因为在之前的过程中已经判断好了
所以,每次新加入一个字符的时候,只需判断加入这个字符后的串的后缀与前面相等长度的串是否满足需求即可。
对于后缀的理解:加入这个字符后,串的长度为k,后缀分别为2,4,6…k/2,分别比较是否满足需求即可
#include<stdio.h>
#define MAX 90
int S[MAX]; //保存第i个位置应该放哪个字符
int n,L;
int dfs(int cur) //返回0表示已经得到解
{
int i,j,k;
if(cur == n)
{
for(i=0;i<cur;i++)
{
printf("%c",'A'+S[i]);
}
printf("\n");
return 0;
}
for(i=0;i<L;i++)
{
int ok=1; //判断方案是否合法
S[cur]=i; //将当前位置设定为i“0==A,1==B,2==C”
for(j=1;2*j<=cur+1;j++) //循环判断长度长度为j*2的后缀
{
int equal=1; //判断后缀中是否有前一半是否等于后一半
for(k=0;k<j;k++)
{
if(S[cur-k]!=S[cur-k-j]) //只要确定了后缀j*2中有一个不相等,则可以确定前一半与后一半不相等
{
equal=0;
break;
}
}
if(equal)
{
ok=0;
break;
}
}
if(ok)
{
if(!dfs(cur+1)) //到这里,说明0到cur位置的困难串已经确立好了,确立下一个位置就好
return 0;
}
}
return 1;
}
int main()
{
while(scanf("%d%d",&n,&L)!=EOF)
{
memset(S,0,sizeof(S));
dfs(0);
}
return 0;
}