回溯法:避免无用判断,强化回溯代码的实现过程
题目的大意就是以字典序为准,排列字符串,但要保证一个字符串中不包含相邻的重复子串。
Problem Description
For example, the sequence ABACBCBAD is easy, since it contains an adjoining repetition of the subsequence CB. Other examples of easy sequences are:
BB
ABCDACABCAB
ABCDABCD
Some examples of hard sequences are:
D
DC
ABDAB
CBABCBA
Input
In order to provide the Quiz
Master with a potentially unlimited source of questions you are asked to write
a program that will read input lines that contain integers n and L (in that
order), where n > 0 and L is in the range , and for each input line prints
out the nth hard sequence (composed of letters drawn from the first L letters
in the alphabet), in increasing alphabetical order (alphabetical ordering here
corresponds to the normal ordering encountered in a dictionary), followed (on
the next line) by the length of that sequence. The first sequence in this
ordering is A. You may assume that for given n and L there do exist at least n
hard sequences.
For example, with L = 3, the first 7 hard sequences are:
A
AB
ABA
ABAC
ABACA
ABACAB
ABACABA
As each sequence is potentially very long, split it into groups of four (4)
characters separated by a space. If there are more than 16 such groups, please
start a new line for the 17th group.
Therefore, if the integers 7 and 3 appear on an input line, the output lines
produced should be
ABAC ABA
7
Input is terminated by a line containing two zeroes. Your program may assume a
maximum sequence length of 80.
Sample Input
30 3
0 0
Sample Output
ABAC ABCA CBAB CABA CABC ACBA CABA
28
在判断当前字符串是否已经存在连续的重复子串,例如判断ABACABA是否包含连续重复子串,并不需要说检查该字符串所有长度为偶数的子串,仅需要做的是判断当前串的后缀。
另外对回溯法来说,一旦本次所要赋值的字符不满足,并且在循环了所有可以在这一次赋值的字符后,仍未满足,就要回溯到上一层,这种情况首先要保证成功次数不要增加(可以将次数设置为全局变量,当然进行完这一组数据后,要记得重新赋值,避免后面的测试数据出现问题,通常全局变量都要在完成一组数据测试后,重新赋初始值)
代码如下
#include<iostream> #include<cstdio> #include<cstring> #define MAXN 200 using namespace std; char alp[MAXN]="AABCDEFGHIJKLMNOPQRSTUVWXYZ";//首先打表方便后面的操作 char ch[MAXN]="#";//处理一个小的细节,当第一个字符时,其实不需要判断前面的字符,为了统一操作,在ch[0]处赋一个与第一个字符一定不同的量 int c=0; bool tag=false;//全局变量,完成字符串的标志 void dfs(int n,int t,int cur) { int i,j,k=1,m,s; bool flag=true; if(n==c)//以次数作为完成的标志 { while(k<=cur-1) { if(k==65) cout<<endl; if(k%4==0&&k!=64&&k!=cur-1)//处理格式要求 cout<<ch[k]<<' '; else cout<<ch[k]; k++; } cout<<endl; cout<<cur-1<<endl; tag=true;//以标示符作为字符串完成的标志 } else { for(i=1;i<=t;i++)//循环此次可以赋值的字符 { flag=true; ch[cur]=alp[i]; for(j=cur/2;j<=cur-1;j++)//字符串判重 { s=0; m=cur-j-1; for(k=0;k<=m;k++) { if(ch[cur-k]==ch[j-k]) s++; } if(s==m+1) { flag=false; break; } } if(flag==false) continue; if(!tag) { c++; dfs(n,t,cur+1);//满足,则字符的长度加一,这也满足字典序的要求,若回溯到这里,那么即回头继续循环可以满足的字符,相当于说字符长度加一个不满足,那么前一个字符往后改,就如同从ABC->ABD(原本要走ABCD的) } if(tag) { // cout<<"return "; return ;//若已完成则一步步回头 } } } } int main() { int n,l; while(cin>>n>>l) { if(n==0&&l==0) break; else dfs(n,l,1); tag=false;//全局变量重新赋初始值 c=0;// 全局变量重新赋初始值 } return 0; }