UVa-129-Krypton Factor(回溯法)

Time limit: 3.000 seconds
限时:3.000秒

Problem
问题

You have been employed by the organisers of a Super Krypton Factor Contest in which contestants have very high mental and physical abilities. In one section of the contest the contestants are tested on their ability to recall a sequence of characters which has been read to them by the Quiz Master. Many of the contestants are very good at recognising patterns. Therefore, in order to add some difficulty to this test, the organisers have decided that sequences containing certain types of repeated subsequences should not be used. However, they do not wish to remove all subsequences that are repeated, since in that case no single character could be repeated. This in itself would make the problem too easy for the contestants. Instead it is decided to eliminate all sequences containing an occurrence of two adjoining identical subsequences. Sequences containing such an occurrence will be called “easy”. Other sequences will be called “hard”.
“超级氪因素大赛”(译注:英国的一档电视心智竞答节目)的主办方雇你来对付那些足智多谋的参赛选手。在比赛的一个环节中,节目主持人将念出一长串的字母来考验选手的记忆能力。因为许多选手都是分析字串模式的高手,为了增加一些比赛的难度,主办方决定不再使用那些含有特定重复子串的字串。但是他们又不能将所有重复的子串都删掉,如果那样的话字串中就不存在两个相同的单字了,这反倒会让问题变的非常简单。为了解决这一问题,他们决定仅删除那些包含相邻重复子串的字串。我们将存在上述相邻重复情况的字串称为“easy”(简单),否则称为“hard”(难)。

For example, the sequence ABACBCBAD is easy, since it contains an adjoining repetition of the subsequence CB. Other examples of easy sequences are:
比方说,字串ABACBCBAD就是一个“easy”,因为它里面有相邻的重复子串“CB”。另举一些“easy”字串的例子如下:

  • BB
  • ABCDACABCAB
  • ABCDABCD

Some examples of hard sequences are:
下面是一个“hard”字串的例子:

  • D
  • DC
  • ABDAB
  • CBABCBA

 

Input and Output
输入和输出

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 1 ≤ L ≤ 26, 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.
为了能给节目主持人提供无限量的问题字串,要求你来写一个程序执行生成运算。程序从输入中读取多行数据,每行包括两个整数n和L(即按此顺序给出),其中n > 0,L的范围是1 ≤ L ≤ 26。根据这些输入,程序要按照字母表升序打印出第n个“hard”字串(由字母表中的前L个字母构成),并在接下来的一行打印这个串的长度。按照上述规则,第一个串应该是“A”。对于给定的n和L,你可以认为第n个“hard”串是一定存在的。

For example, with L = 3, the first 7 hard sequences are:
比方说,当L = 3时,头7个“hard”字串为:

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.
字串可能很长,因此要将它们分成4个字为一组,中间用空格隔开。如果超过16组,则换一行,再接着输出第17组。

Therefore, if the integers 7 and 3 appear on an input line, the output lines produced should be:

按照此格式,对于输入的整数7和3,输出应该为:

ABAC ABA
7

Input is terminated by a line containing two zeroes. Your program may assume a maximum sequence length of 80.
输入由一行两个零表示结束。你的程序可以限定最大的字串长度为80。

 

Sample Input
输入示例

30 3
0 0

Sample Output
输出示例

ABAC ABCA CBAB CABA CABC ACBA CABA
28

 

Analysis
分析

很经典的递归调用过程,难度适中,推荐先认真的做一下再来看解析。题目本身不是很好懂,需要认真思考才能明白其意图。

避免相邻重复的子串很好办:如果生成字符串是逐个在后面添加字符的话,只要每次在添加后检查当前串是否满足条件就可以了。不满足的不能添加,这样就能保证字符串里没有任何相邻重复的子串。检查的方法是从长度1开始,检查最后1个字符及其前面1个字符是否相等,再将长度增为2,检查最后2个字符及其前面2个字符是否相等,以此类推。

题目要求按字母表顺序生成字串,通过观查给出的例子(7 3)可知字串都是以A开始,逐个向后生成。每次在末尾添加一个尽量靠前的(在ASCII表中较小的)又可以满足要求的字母,如果都不满足要求则向前回溯,将前一个字母增大再试。每次成功的添加一个都算作生成了一个字串。直到生成的字串数达到给定的数量n。

思路理清后代码就很容易写了,算是一个小程序。有一点要注意,输出时一定要按照要求的格式,每过四个字符加一个空格,达到4×16的字符后不要加空格,而要加一个回车。后面的仍是每过四个加一个空格。千万注意!


#include<cstdio>
using namespace std;

int S[100];
int n,L,cnt;	
int serch(int cur){
/*	for(int i=0;i<cur;i++){
			if(i)
				if(i%4==0)	printf(" ");
			printf("%c",'A'+S[i]);
		}
	printf("\n");*/	
	if(cnt++ == n){			//先比较再自加 
		for(int i=0;i<cur;i++){
			if(i){
				if(i%64){
					if(i%4==0)	printf(" ");
				}
				else printf("\n");
			}
			printf("%c",'A'+S[i]); 
		}
		printf("\n%d\n",cur);
		return 0;
	}
	for(int i=0;i<L;i++){	//对每个字母都进行尝试 
		S[cur]=i;
		int ok=1;
		for(int j=1;j*2<=cur+1;j++){	//尝试长度为j*2的后缀 
			int equal=1;
			for(int k=0;k<j;k++)
				if(S[cur-k]!=S[cur-k-j]){ 
					equal=0; break; 
				}
			if(equal){	ok=0;	break; }	//如果后一半等于前一半,不符合要求 
		}
		if(ok && !serch(cur+1)) return 0;	//递归搜索,如果已经找到解,直接退出 
	}
	return 1;
}
int main(){ 
	while(scanf("%d%d",&n,&L)!=EOF && n+L){
		cnt=0;
		serch(0);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值