算法——DFS

前言
由于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);
}```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值