前言
由于DFS没有具体的模板,所以通过具体的题目来了解该算法。
---------------------递归实现组合型枚举---------------------------------------
从 1∼n 这 n 个整数中随机选出 m 个,输出所有可能的选择方案。
输入格式
两个整数 n,m ,在同一行用空格隔开。
输出格式
按照从小到大的顺序输出所有方案,每行 1 个。
首先,同一行内的数升序排列,相邻两个数用一个空格隔开。
其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面(例如 1 3 5 7 排在 1 3 6 8 前面)。
数据范围
n>0 ,
0≤m≤n ,
n+(n−m)≤25
输入样例:
5 3
输出样例:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
#include<iostream>
using namespace std;
const int N=30;
int path[N];//用来存储已经排好的数字
bool re[N];//用来判断当前数字是否排过
int n,k;
void dfs(int u)//u表示当前排到了第几位
{
if(u==k)//排到了第n位,表示已经排完,输出拍好的序列
{
for(int i=0;i<k;i++) cout<<path[i]<<" ";
cout<<endl;
return ;
}
for(int i=1;i<=n;i++)//依次排入1-n的数字
{
if(!re[i]&&i>path[u-1])//如果数字未被使用,则排入
{
path[u]=i;//当前位排入i
re[i]=true;//将数字i标注为使用过
dfs(u+1);//进行递归
re[i]=false;//还原
}
}
}
int main()
{
cin>>n>>k;
dfs(0);
}
-------------------------------------------小猫爬山-------------------------------------
翰翰和达达饲养了 N 只小猫,这天,小猫们要去爬山。
经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了(呜咕>_<)。
翰翰和达达只好花钱让它们坐索道下山。
索道上的缆车最大承重量为 W,而 N 只小猫的重量分别是 C1、C2……CN。
当然,每辆缆车上的小猫的重量之和不能超过 W。
每租用一辆缆车,翰翰和达达就要付 1 美元,所以他们想知道,最少需要付多少美元才能把这 N 只小猫都运送下山?
输入格式
第 1 行:包含两个用空格隔开的整数,N 和 W。
第 2..N+1 行:每行一个整数,其中第 i+1 行的整数表示第 i 只小猫的重量 Ci。
输出格式
输出一个整数,表示最少需要多少美元,也就是最少需要多少辆缆车。
数据范围
1≤N≤18,
1≤Ci≤W≤108
输入样例:
5 1996
1
2
1994
12
29
输出样例:
2
#include<iostream>
#include<algorithm>
using namespace std;
const int N=20;
int path[N];
int n,w,num[N],d=0,ans=99;//ans表示需要的总缆车数,d表示当前需要的缆车数
void dfs(int u,int d)
{if(d>=ans) return;//当当前需要的缆车数大于之前已经得出的总缆车数,则当前递归无意义,剪去
if(u==n) //当当前已经排好的猫咪数u等于总猫咪数,需要的缆车总数就等于当前需要的缆车数
{
ans=d;
return;
}
for(int i=0;i<d;i++)//
if(num[u]+path[i]<=w)//如果当前已有重量加上下一只的重量小于等于w,则可以放入当前缆车
{
path[i]+=num[u];
dfs(u+1,d);//放入的猫咪加一,继续寻找
path[i]-=num[u];//还原
}
path[d]=num[u];//当缆车放不下,重新开一个新的缆车,装装不下的那只猫咪
dfs(u+1,d+1);//猫咪数加一,缆车数加一
path[d]=0;//还原
}
int main()
{
cin>>n>>w;
for(int i=0;i<n;i++) cin>>num[i];
sort(num,num+n);
reverse(num,num+n);//将猫咪按重量从大到小排列
dfs(0,0);
cout<<ans<<endl;
}
优化的地方:
1.当当前缆车数量大于已知的最小数量,当前递归进行下去也没有意义。
2.将重量大的猫咪先排,可以减少最先搜索的树的分支,减少递归次数。
-----------------------------------------------火车进栈----------------------------------------------------------
这里有 n 列火车将要进站再出站,但是,每列火车只有 1 节,那就是车头。
这 n 列火车按 1 到 n 的顺序从东方左转进站,这个车站是南北方向的,它虽然无限长,只可惜是一个死胡同,而且 站台只有一条股道,火车只能倒着从西方出去,而且每列火车必须进站,先进后出。
也就是说这个火车站其实就相当于一个栈,每次可以让右侧头火车进栈,或者让栈顶火车出站。
车站示意如图:
出站<—— <——进站
|车|
|站|
|__|
现在请你按《字典序》输出前 20 种可能的出栈方案。
输入格式
输入一个整数 n,代表火车数量。
输出格式
按照《字典序》输出前 20 种答案,每行一种,不要空格。
数据范围
1≤n≤20
输入样例:
3
输出样例:
123
132
213
231
321
#include<iostream>
#include<vector>
#include<stack>
using namespace std;
const int N=22;
int state3=1;//表示未进站的车
vector<int> state1;//表示已经出去的车
stack<int> state2;//表示在站内的车
int n,k=20;
void dfs()
{
if(!k) return;//因为输出前20个样例
if(state1.size()==n)//当出去的车的数量等于车的总数,输出当前排好的序列
{k--;
for(auto x:state1) cout<<x;
cout<<endl;
return;
}
if(state2.size())//当当前站内的车的数量大于0,将站内的车整出去
{
state1.push_back(state2.top());
state2.pop();
dfs();
state2.push(state1.back());//还原
state1.pop_back();
}
if(state3<=n)//当前未进站的车的数量小于最大数字时,将车放进站内
{
state2.push(state3);//将车开进站
state3++;
dfs();
state3--;//还原
state2.pop();
}
}
int main()
{
cin>>n;
dfs();
}
银老板家的电梯
描述
众所周知银老板是喀兰贸易的老大,银老板家也很有钱,上下楼都要用电梯,但是电梯里面没有按钮,电梯外面只
有上和下,按上你就会上升mi层,按下你就会下降mi层,即到达i+mi层或者i-mi层,i是你的当前楼层。现在银老板在
p层,他想要去t层,请你帮帮银老板他最少需要按多少下按钮可以到达目的地。说不定他就来到你岛了呢?如果你
还没有理解题意的话好吧我就举个例子:比如银老板在第2层,想要去第5层,且m依次为4,1,2,3,4;则他
最少需要按2次(连续按2次上或者先按1次下再按1次上)才能到达目的地。(楼层>=1)
输入
第一行一个n,p,t(1<=n,p,t<=200)
第二行n个整数m1,m2.......mn;(0<=mi<=50)
输出
一个整数表示从p层到t层最少需要按多少次。如果不能到达输出-1。
输入样例 1
5 2 5
4 1 2 3 4
输出样例 1
2
输入样例 2 ``
6 3 2
1 2 3 4 5 6
输出样例 2
-1
#include<iostream>
#include<algorithm>
using namespace std;
const int N=220;
int num[N];
bool re[N];
int n,b=99999,a=0,p,t;
void go(int k,int a)
{
if(a>b) return;
if(!re[k+num[k]]&&k+num[k]<=n) {
re[k+num[k]]=true;
a++;
go(k+num[k],a);
a--;
re[k+num[k]]=false;
}
if(!re[k-num[k]]&&k-num[k]>0) {
re[k-num[k]]=true;
a++;
go(k-num[k],a);
re[k-num[k]]=false;
a--;
}
if(k==t) b=a;
}
int main()
{
cin>>n>>p>>t;
for(int i=1;i<=n;i++)
cin>>num[i];
re[p]=true;
go(p,0);
if(b==99999)
cout<<-1<<endl;
else
cout<<b<<endl;
}
思路:
用一个布尔数组来存储各层的状态,避免去过的层重复去,需要适当的剪枝,不然可能超时。在每一层都有两个抉择,上和下。如果行动后到达的那层在1-n之间,且之前没有光顾过,则可以到达。递归后取最小的操作数就行。
n-皇后问题
n− 皇后问题是指将 n 个皇后放在 n×n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处
于同一行、同一列或同一斜线上。
现在给定整数 n,请你输出所有的满足条件的棋子摆法。
输入格式
共一行,包含整数 n。
输出格式
每个解决方案占 n 行,每行输出一个长度为 n 的字符串,用来表示完整的棋盘状态。
其中 . 表示某一个位置的方格状态为空,Q 表示某一个位置的方格上摆着皇后。
每个方案输出完成后,输出一个空行。
注意:行末不能有多余空格。
输出方案的顺序任意,只要不重复且没有遗漏即可。
数据范围
1≤n≤9
输入样例:
4
输出样例:
.Q..
...Q
Q...
..Q.
..Q.
Q...
...Q
.Q..
#include<iostream>
using namespace std;
int n;
const int N=15;
char str[N][N];
bool col[N],dui[N],redui[N];
void dfs(int u)
{
if(u==n)
{
for(int i=0;i<n;i++) puts(str[i]);
cout<<endl;
return;
}
for(int i=0;i<n;i++)
{
if(!col[i]&&!dui[u+i]&&!redui[n-u+i])
{
str[u][i]='Q';
col[i]=dui[u+i]=redui[n-u+i]=true;
dfs(u+1);
col[i]=dui[u+i]=redui[n-u+i]=false;
str[u][i]='.';
}
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
str[i][j]='.';
dfs(0);
}```