DFS(深度优先搜索)

dfs可以用递归来写,也可以用来写

dfs很难找到最优解,只用来找到某个解,内存消耗较小

dfs如果需要回溯,就需要取消标记

void dfs(int step){

边界

  

遍历

}

模板 

边界 输出结果       

递归出口,打印结果

if(判断边界) {//终止条件

......

return;(返回上一步)
}

遍历 搜索

for((int i = 0; i < 可扩展的路径数; i++){//遍历
......

book[i] = 1;(标记)

dfs(step + 1);(递归)//下一种情况

book[i] = 0;(取消标记)

}

全排列——P1706

#include<bits/stdc++.h>
using namespace std;

int n;//经验:由于dfs函数中要用到变量n,故n一般都定义为全局变量 
int res[100];//结果数组,存储结果
int vis[100];//标记数组,0表示没有放入,1表示已经放入
 
void dfs(int step)//step记录步数,当前第几个盒子 (就可以表示下标) 
{
	//边界
	//递归出口,打印结果(n = 3 -> step = 4)
	//递归出口的第二种写法:step>n 
	if(step==n+1)//到达最后一个盒子的下一个 
	{
		for(int i=1;i<=n;i++) printf("    %d",res[i]);
		puts(" "); //换行 cout<<endl
		return; //撞墙回来 
	}
	
	//遍历 
	//卡片 
	//递归搜索1-n全排列 
	for(int i=1;i<=n;i++)//每张卡片只能用一次 
	{
	   if(vis[i]==0)//没有用过,没有放入盒子
	   {
	     res[step]=i;//卡片i放入盒子中 ,模拟结果数组 
	     vis[i]=1;//标记 
	     
	     dfs(step+1);//递归 ,下一个盒子 
	     
	     vis[i]=0;//取消标记 ,边界回溯 
	   } 
    } 
}  
 
int main()
{
	cin>>n;
	dfs(1); //第一个盒子开始搜索 
	return 0;
}

 八皇后——P1219

同一行,同一列以及同一对角线(包括所有的主对角线和副对角线)只允许一个皇后存在

 分析

先放第一行元素,在放第二行的元素,……,最后放第n的元素。这样做的好处是,我们在搜索时可以只枚举列,而不用枚举行

 m2[i+j]: 2 3 4....2n

m3[i-j+n]:1 2 3 ....2n-1

#include<bits/stdc++.h>
using namespace std;
int n,m[30],m1[30],m2[30],vis[30];
int cnt = 0;//皇后一共有cnt种摆法

void print(){//打印序列 
    if(cnt<=3){
    	for(int i=1;i<=n;i++){
	    	cout<<vis[i]<<" ";
          }
	    	cout<<endl;
	}

}
void dfs(int step)
{
	if(step>n){
		cnt++;
		print();
	    return;	
	}
	for(int j=1;j<=n;j++)
	{   
		if(m[j]||m1[step+j]||m2[step-j+n])continue;
		    vis[step]=j;//记录第i行放在第j列
		    m[j]=1;
		    m1[step+j]=1;
		    m2[step-j+n]=1;
			
			dfs(step+1); 
			m[j]=0;
		    m1[step+j]=0;
		    m2[step-j+n]=0;
		
	}

 } 
 
int main(){
	cin>>n;
	dfs(1);
	cout<<cnt; 
	return 0;
}

P1019 [NOIP2000 提高组] 单词接龙

 

分析 :

atoucheatactactouchoose  可以重复用

#include<bits/stdc++.h>
using namespace std;
 
int n,ans=0,t[22];
string a[22];
char c;	//开头字母 

int check(string s,string t){//检查两个字符串的首尾重合程度
	int len = min(s.length(),t.length());
	for(int i=1;i<len;i++){//检查所有长度 
		string s1=s.substr(s.length()-i,i);//s字符串取尾巴,从末尾向前 
		string s2=t.substr(0,i);//t字符串取开头 
		if(s1==s2) return i; 
	}
	return 0;
}
void dfs(int p,int len){//位置,长度 
	ans=max(ans,len); 
	for(int i=1;i<=n;i++){
		if(t[i]>=2) continue;//用过两次不能再用了 
		//检查两个字符串的首尾重合程度
		 int cnt=check(a[p],a[i]);
		 if(cnt>0){//表示有重合 
		 	t[i]++;
		 	//原先的加上后来的减去重合数
		 	//at tact =attact=2+4-1=5 
		 	dfs(i,len+a[i].length()-cnt);  
		 	t[i]--;//回溯 
		 }
	}
}

int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}

	cin>>c;
	for(int i=1;i<=n;i++){
		if(a[i][0]==c){//字符串的首字母是t,表示可以以t开头
		    memset(t,0,sizeof(t));//清掉 
		    t[i]=1; 
			dfs(i,a[i].length()); //开始搜索 ,从i开始,目前长度 
		}
	}
	cout<<ans<<endl;//输出最长龙的长度 
	return 0;
}

P5194 [USACO05DEC]Scales S 

 

12界蓝桥杯试题G.砝码称重 

 

 

P5440 【XR-2】奇迹 

 

 P1378 油滴扩展

 

 2017蓝桥杯省赛真题 迷宫

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值