算法竞赛入门经典:第七章 暴力求解法 7.13困难的串

来源:互联网 发布:建模 软件p 编辑:程序博客网 时间:2024/05/17 01:12
/*困难的串:如果一个字符串包含两个相邻的重复子串,则称它是“容易的串”,其他串成为“困难的串”。例如:BB,ABCDACABCAB,ABCDABCD都是容易的,而D、DC、ABDAB、CBABCBA都是困难的。输入正整数n和L,输出由前L个字符组成的、字典序第n个小的困难的串。例如,当L=3时,前7个困难的串分别为:A、AB、ABA、ABAC、ABACA、ABACAB、ABACABA。输入保证答案不超过80个字符输入:7 330 3输出:ABACA BAABACA BCACB ABCAB ACABC ACBAC ABA分析:从左到右一次考虑每位置上的字符。关键:如何判断当前字符串是否存在连续的重复子串。例如,如何判断ABACABA是否包含连续重复子串呢?方法1:检查所有长度为偶数的子串,判断前一半=后一半方法2:只需判断当前串的后缀八皇后的教训:只判断当前皇后与之前的皇后是否冲突,而不判断之前的皇后是否互相冲突思路:1 大致用到了全排列,都是在原来基础上进行累加,但不知何时加B何时加C2 非相邻重复子串怎么筛选条件(判断当前串的后缀的后半部分与前半部分是否连续且重复,不需要完整判断整个字符串)*//*关键:1 if(cnt++ == n)//用cnt累计字典序第n个困难串2 printf("%c",iArr[i] + 'A');//由于iArr[i]是整数,加上字符'A'之后,确保字符是从A开始的3 return 0;//这里使用返回值,是为后面判断是否已经达到跳出条件做准备4 for(int m = 0; m < L; m++)//L表示困难串的长度5 for(int j = 1; 2*j <= pos+1; j++)//这里是对2*j长度的当前串的后缀进行判断6 for(int k = 0 ; k < j ; k++)//确保连续的能被判断到{if(iArr[pos-k] != iArr[pos-k-j]){isEqual = false;//不是重复相等的情况break;}}7 if(isDiff)//如果是困难的串,递归调用下一趟{if(!dfs(pos+1,n,L,iArr))//如果已经找到字典序第n小的困难串,输出{return 0;}}*/#include <stdio.h>#include <stdlib.h>#define MAXSIZE 1024int cnt;int dfs(int pos,int n,int L,int* iArr){if(cnt++ == n)//用cnt累计字典序第n个困难串{for(int i = 0 ; i < pos ; i++){printf("%c",iArr[i] + 'A');//由于iArr[i]是整数,加上字符'A'之后,确保字符是从A开始的}putchar('\n');return 0;//这里使用返回值,是为后面判断是否已经达到跳出条件做准备}else{for(int m = 0; m < L; m++)//L表示困难串的长度{iArr[pos] = m;bool isDiff = true;for(int j = 1; 2*j <= pos+1; j++)//这里是对2*j长度的当前串的后缀进行判断{bool isEqual = true;for(int k = 0 ; k < j ; k++)//确保连续的能被判断到{if(iArr[pos-k] != iArr[pos-k-j]){isEqual = false;//不是重复相等的情况break;}}if(isEqual)//如果相等,说明是重复的,说明是简单串,不符合要求{isDiff = false;break;}}if(isDiff)//如果是困难的串,递归调用下一趟{if(!dfs(pos+1,n,L,iArr))//如果已经找到字典序第n小的困难串,输出{return 0;}}}}return 1;//如果没有找到就输出}int main(int argc,char* argv[]){int n,L;while(EOF != scanf("%d %d",&n,&L)){int iArr[MAXSIZE];cnt = 0;dfs(0,n,L,iArr);}system("pause");return 0;}

0 0