**前言:**当普通dfs搜索答案时,有时会有搜索的深度较深状态较多,而答案所在的深度却比较小的情况,这样会有大量搜索浪费在无用但是又递归层数很大的情况上。对此可以在dfs的时候限定一个深度的状态,这个深度是从小到大枚举的,直到搜到答案。
一、poj3141
题目大意是给定一个正整数n,求经过多少次乘法或除法运算可以从x得到xn,可以使用中间得到的结果。
思路:
起始只有x的一次方,所以通过乘除得到的值应该用数组存起来后续可以循环遍历。开始只设定递归一次,判断是否达到目的,没有则多给一次递归机会,即deep+1。因为幂函数运算乘就可以做加法,除可以做减法,所以对于之前存入数组的每个值遍历时都dfs两种情况。
还有一个很重要的剪枝,if(n<<(deep-m)<ans)//deep-m为剩余可走的步数,如果连n的deep-m次方都比ans小,则不可能。没有这个剪枝,十位数的数据都出不来。
#include <bits/stdc++.h>
using namespace std;
int vis[10000],a[10000];
int deep=0,ans;
bool dfs(int m,int n)
{
//cout<<m<<" "<<n<<" "<<deep<<" "<<ans<<endl;
if(n<<(deep-m)<ans)//deep-m为剩余可走的步数,如果连n的deep-m
次方都比ans小,则不可能
return false;
if(m==deep&&n==ans)//到了深度就判断是否为目标值
return true;
if(m>=deep)//超过深度直接返回假
return false;
a[m]=n;//将当前值记入数组中,因为后续每一步都可以用前面算得的值
for(int i=0;i<=m;i++)//遍历数组
{
int x=n+a[i];//乘法
// if(vis[a[i]])
if(dfs(m+1,x))
return true;
x=n-a[i];//除法
// if(vis[a[i]])
if(dfs(m+1,x))
return true;
}
return false;//没返回成功,就返回假嘛,因为一定要
返回值的,不然while里面没办法判断
}
int main()
{
while(cin>>ans)
{
deep=0;//一开始深度设置为0
if(ans==0)
break;
memset(vis,0,sizeof(vis));
memset(a,0,sizeof(a));
while(1)//只要没找到答案深度加一,继续找。
{
if(dfs(0,1))
break;
deep++;
}
cout<<deep<<endl;
}
}
二、DNA sequence
题目大意:就是给出N个DNA序列,要求出一个包含这n个序列的最短序列是多长。
**题目思路:**这道题还是有点难啊,感谢大神Sly_461的解析,原文链接为
https://blog.csdn.net/acmer_sly/article/details/52673575(下面的代码就是他的)
但还是有几点需要注意
一、用二位字符数组储存多个DNA
二、用pos数组储存每个DNA搜索到哪个位置了
三、设置搜索深度,但起始深度为最长的那个DNA,因为最后的序列肯定得包含它嘛!
四、当pos数组中全为各个DNA长度时,完成搜索,退出搜索
五、每次dfs都是从四个字母中选一个,判断选的字母是否对Pos数组有贡献,有则使flag为1,继续下一次dfs。没贡献则没意思,不用继续dfs。
六、在函数中另外定义一个pos数组记录各个DNA的新进度,用pos传入参数,避免了回溯的复杂过程。
#include<stdio.h>
#include<string.h>
int n;
int ans; //最后答案
char str[10][10]; //记录n个字符串
int deep; //搜索深度
char DNA[4]={'A','T','C','G'}; //四种可能
int Max(int x,int y){
if(x>y)return x;
else return y;
}
void Dfs(int index,int len[]){
if(index>deep)return; //大于限制的深度,不用往下搜索
int i,j,maxx=0; //预计还要匹配的字符串的最大长度
for(i=0;i<n;i++){
maxx=Max(strlen(str[i])-len[i],maxx);
}
if(maxx==0){ //条件全部满足即为最优解
ans=index;
return;
}
if(index+maxx>deep) //剪枝
return; //当前的深度+最少还有加深的深度是否大于限制的长度,若是,则退回
for(i=0;i<4;i++){
int flag=0;
int pos[10];
for(j=0;j<n;j++){
if(str[j][len[j]]==DNA[i]){//表示该字母可以往下搜索
flag=1;
pos[j]=len[j]+1;
}
else pos[j]=len[j];
}
if(flag)Dfs(index+1,pos);
if(ans!=-1)return; //已经搜到最优解 不必再往下搜
}
}
int main()
{
int t,i;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
deep=0;
for(i=0;i<n;i++){
scanf("%s",str[i]);
deep=Max(deep,strlen(str[i]));//找出最长的串的长度,作为初始时的迭代DFS的限制
}
ans=-1;
int pos[10]={0}; //记录n个字符串目前匹配到的位置
while(1){
Dfs(0,pos);
if(ans!=-1)
break;
deep++; //加深迭代
}
printf("%d
",ans);
}
return 0;
}