紫书第7章-暴力dfs

E-Krypton Factor

Description

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 sequenace 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”.

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
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 from standard input and will write to standard output.

Input
Each input line contains integers n and L (in that order), where n>0 and L is in the range 1≤L≤26. Input is terminated by a line containing two zeroes.

Output
For each input line prints out the n-th 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.

As such a 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.

Your program may assume a maximum sequence length of 80.

For example, with L=3, the first 7 hard sequences are:

A

AB

ABA

ABAC

ABACA

ABACAB

ABACABA

Samples
Input
7 3
30 3
0 0
Output
ABAC ABA
7
ABAC ABCA CBAB CABA CABC ACBA CABA
28

题目大意

当一个字符串中存在连续且相同的子串时则成为“简单字符串”
否则称为复杂字符串
给出N L

求出由 前L个大写字母 组成的 第N 个 复杂字符串

注意事项
题目包含一些隐藏条件
根据样例1
7 3 → ABACABA 如果继续往后添加字母,不管怎么添加都不符合复杂字符串的条件
根据样例2
28 3 → ABACABC…可知,当字符串末尾不能再添加任何字母时,则改变最后一个字母

思路
处理问题的总体思想,与”八皇后问题“相似,都是判断新加入的字符是否符合条件

具体思路

用cur+1记录字符串的长度,cur是当前字符串的末位置(从0开始)
用cnt记录这是当前第几个复杂字符串

dfs 深度优先判断
暴力枚举,首先枚举当前位置的字母 (A,B,C,D…)
其次枚举本次我要进行检查的字母数量 (1,2,3,…) (j)

(当然检查的字母的数量不能超过字符串总长的一半)

然后一组一组的进行检查 (k)
例如
ABA →ABAC 的过程
首先在末尾处 添加一个 A
则变成了 ABAA 此时我们要检查1个字符
则将 末尾的两个 A 进行检查
发现末尾两个A相等之后,不符合规矩直接结束了,不需要进行检查两个字符的操作
然后枚举 添加 字母 B
变成 ABAB 后,首先检查一个字符 ,发现 A!=B,暂时合法
然后检查两个字符 此时 对应字母的位置发生了变化
A和A对应,B和B对应
发现相等,不符合条件,所以最后添加了一个C
经过检查之后 C符合条件

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
int n,l;
int haha[maxn];
int cnt;
int dfs(int cur)
{
	if(cnt++==n)
	{
		//cout<<cur<<endl;
		for(int i=0;i<cur;i++){//0 1 2 3 
			if(i%4==0&&i!=0&&i!=64) //题目要求四个四个一起输出!,并且最多一行输出64个组! 
			printf(" "); //这个空格是先输出原则,而不是后输出原则!!!!! 
			
			printf("%c",haha[i]+'A');//还原 
			if((i+1)%64==0) 
			printf("\n");//这个\n是后输出原则! 
		}
		if(cur!=64) //如果这里不加条件,就会多输出一个回车,PE! 
		printf("\n");
		printf("%d\n",cur);
		return 0;
	}
	else
	{
		for(int i=0;i<l;i++)//枚举每一个字符  A  B  C 
		{
			haha[cur]=i;//cur是当前遍历的位置,真实的字符串长度其实是cur+1;
			bool flag1=1;
			for(int j=1;j*2<=cur+1;j++)//所要进行检查的子串的长度
			{
				bool flag2=1;
			    for(int k=0;k<j;k++)//  更改对应字符的位置
			    {
			    	if(haha[cur-k]!=haha[cur-k-j])
			    	{
			    		flag2=0;
			    		break;
					}
				}
			if(flag2==1)
				{
				  flag1=0;
				  break;
		}}
		if(flag1==1)
		  if(dfs(cur+1)==0) //4 
		  return 0;
	    }
	}
	return 1;
}
int main()
{
	while(cin>>n>>l&&n&&l)
	{
		cnt=0;
		dfs(0);
	}
	return 0;
}

L-Power Calculus

Description
Starting with x and repeatedly multiplying by x, we can compute x31 with thirty multiplications:

x2=x×x,x3=x2×x,x4=x3×x,…,x31=x30×x.
The operation of squaring can appreciably shorten the sequence of multiplications. The following is a way to compute x31 with eight multiplications:

x2=x×x,x3=x2×x,x6=x3×x3,x7=x6×x,x14=x7×x7,
x15=x14×x,x30=x15×x15,x31=x30×x.
This is not the shortest sequence of multiplications to compute x31. There are many ways with only seven multiplications. The following is one of them:

x2=x×x,x4=x2×x2,x8=x4×x4,x10=x8×x2,
x20=x10×x10,x30=x20×x10,x31=x30×x.
There however is no way to compute x31 with fewer multiplications. Thus this is one of the most efficient ways to compute x31 only by multiplications.

If division is also available, we can find a shorter sequence of operations. It is possible to compute x31 with six operations (five multiplications and one division):

x2=x×x,x4=x2×x2,x8=x4×x4,x16=x8×x8,x32=x16×x16,x31=x32÷x.
This is one of the most efficient ways to compute x31 if a division is as fast as a multiplication.

Your mission is to write a program to find the least number of operations to compute xn by multiplication and division starting with x for the given positive integer n. Products and quotients appearing in the sequence of operations should be x to a positive integer’s power. In other words, x−3 , for example, should never appear.

Input
The input is a sequence of one or more lines each containing a single integer n. n is positive and less than or equal to 1000. The end of the input is indicated by a zero.

Output
Your program should print the least total number of multiplications and divisions required to compute xn starting with x for the integer n. The numbers should be written each in a separate line without any superfluous characters such as leading or trailing spaces.

Samples
Input
1
31
70
91
473
512
811
953
0
Output
0
6
8
9
11
9
13
12

题目大意

问最少经历几次乘法或者除法 可以算出 X的第N次幂

x2=x * x
x4=x2 * x2
x8=x4 * x4
x16=x8 * x8
x32=x16 * x16
x31=x32/x

综上所述,算出x31次幂最少需要6次运算

具体思路
还是进行暴力dfs
首先枚举 最少算的次数为 depth
当前已经计算过的次数为 now

进行dfs(now,depth) (刚开始now=0)

那么,如果一个数字 以最快速度 相乘的话
则最大值就是 1<<(dpeth-now) ( 2的 dpeth-now次幂)
如果这个最大值数字都不能到达 n 次幂
所以一定不符合条件,结束。

如果now>depth,则也说明所做的假设不符合事实

我们设置一个名为dp数组
dp[pos=0]=1,dp[i]代表x经历i 次运算,我们可以算出的x的幂值。
dp[0]代表不经过任何运算,在最开始我们就可以使用 x的1次幂

然后将dp[pos]=n作为 dfs(now.,depth)=1 的结束条件,因为最后一次运算正好算出了 x的n次幂

在每一次dfs时 在进行一次暴力枚举
枚举当前 dp[pos]的值,dp[pos]可能等于 dp[pos-1]和 1-(pos-1)范围内当中某一项的和,( 模拟乘法过程 )
因为假如 你现在 已经拥有 x^1 x^2 x^3 你的下一项可能是 x^6 x^5 x^4

然后再次向更深处dfs,同时now的值+1

然后在对减法进行模拟
dp[pos]的值,也可能是通过减法减出来的 ( 模拟除法过程 )
因为假如 你现在拥有 x^1 x^2 x^4 x^8 x^16 那么下一项可能是 x^15 x^14
x^12…
dp[pos]=abs(dp[pos-1]-dp[i])

然后在向更深处dfs,同时now的值+1

确保每一个位置 的每一种可能都被能被我们考虑进去

然后当dfs返回值为1时,我们输出depth(计算的次数)
即为正确答案。

#include<bits/stdc++.h>
using namespace std;
int n;
int dp[10001];
int pos;
int dfs(int now,int depth)
{
	if(now>depth)
	return 0;
	if(dp[pos]<<(depth-now)<n)
	return 0;
	if(dp[pos]==n)
	return 1;
	
	pos++;
	for(int i=0;i<pos;i++)
	{
		//刚开始模拟乘法!
		dp[pos]=dp[pos-1]+dp[i];
		
		if(dfs(now+1,depth)==1)
		return 1; 
		
		//开始模拟除法! 
		dp[pos]=abs(dp[pos-1]-dp[i]);
		if(dfs(now+1,depth)==1)
		return 1;
		
	}
	pos--;
	return 0;
}
int main()
{
    while(cin>>n&&n)
	{
		int depth;
		for(depth=0;;depth++)
		{
		dp[pos=0]=1;
	   if(dfs(0,depth)==1)
	    break;
	   }
	   cout<<depth<<endl;
	}	
	return 0;
}

学习不易,你我共勉之

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值