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蓝桥杯省赛真题 迷宫