- 题目:
- 分析与解答:
题目:
如果一个字符串包含两个相邻的重复子串,则称它是“容易的串”,其他串成为“困难的串”。例如:BB,ABCDACABCAB,ABCDABCD都是容易的,而D、DC、ABDAB、CBABCBA
都是困难的。
输入正整数n和L,输出由前L个字符组成的、字典序第n个小的困难的串。例如,当L=3时,前7个困难的串分别为:A、AB、ABA、ABAC、ABACA、ABACAB、ABACABA。
输入保证答案不超过80个字符
输入:
7 3
30 3
输出:
ABACA BA
ABACA BCACB ABCAB ACABC ACBAC ABA
分析与解答:
在回溯算法中,应注意避免不必要的判断,八皇后问题中,只需判断新皇后和之前的皇后是否冲突,而不必判断以前的皇后是否相互冲突。
这一题只需判断当前串的偶数项后缀是否对称
BB,长度为1*2的后缀对称
ABCDACABCAB,长度为3*2的后缀对称
ABCDABCD长度为4*2的后缀对称
像这些对称的串,必定不为困难的串
#include<stdio.h>
#include<string.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位置的困难串已经确立好了,确立下一个位置就好//如果已经找出字典序第n小的串,那么dfs(cur+1)返回0,此时直接退出 return 0;}}return 1;
}
int main()
{while(scanf("%d%d",&n,&L)!=EOF){memset(S,0,sizeof(S));dfs(0);}return 0;
}