深搜+迭代

**前言:**当普通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;
}
原文地址:https://www.cnblogs.com/iss-ue/p/12679637.html