【算法专栏01】深度优先搜索(又名:搜索与回溯算法)例题

欢迎同学们查看https://blog.csdn.net/2301_80065984/category_12688940.html (算法专栏)其他文章

目录

【搜索与回溯算法】组合的输出

题目描述

输入

输出

样例输入

样例输出

 题解

【搜索与回溯算法】装载问题

题目描述

输入

输出

样例输入

样例输出

数据范围限制

题解

【搜索与回溯算法】迷宫问题

题目描述

输入

输出

样例输入

样例输出

题解

【搜索与回溯算法】马的走法

题目描述

输入

输出

样例输入

样例输出

题解

结尾


【搜索与回溯算法】组合的输出

题目描述

排列与组合是常用的数学方法,其中组合就是从n个元素中抽出r个元素(不分顺序且r<=n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取r个数。
现要求你用递归的方法输出所有组合。
例如n=5,r=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

输入

一行两个自然数n、r(1<n<21,1<=r<=n)。

输出

所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素之间用空格隔开,所有的组合也按字典顺序。

样例输入

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

 题解

我们只需要将其每一位都暴力枚举即可,注意需要使用vis数组检测这个数字是否用过

代码见下:

#include<bits/stdc++.h>
using namespace std;
int n,r;
int a[30],vis[30];
void dfs(int x,int y)//搜索函数
{
	if(x>r)
	{
		for(int i=1;i<=r;i++)
		{
			printf("%d ",a[i]);
		}
		printf("\n");
		return;
	}
	for(int i=1;i<=n;i++)//每种情况都试一遍
	{
		if(vis[i]==0&&i>a[x-1])//判断可行性
		{
			a[x]=i;
			vis[i]=1;
			dfs(x+1,r);//搜索
			vis[i]=0;//回溯
		}
	}
}
int main()
{
	scanf("%d%d",&n,&r);
	dfs(1,r);//调用函数
	return 0;
}

【搜索与回溯算法】装载问题

题目描述

有一批共n个集装箱要装上艘载重量为c的轮船,其中集装箱i的重量为wi。找出一种最优装载方案,将轮船尽可能装满,即在装载体积不受限制的情况下,将尽可能重的集装箱装上轮船。

输入

第一行有2个正整数n和c。n是集装箱数,c是轮船的载重量。接下来的1行中有n个正整数,表示集装箱的重量。

输出

将计算出的最大装载重量输出

样例输入

5 10
7 2 6 5 4

样例输出

10

数据范围限制

n<=35,c<=1000

题解

我们只需要将每个集装箱都进行尝试要和不要这两种处理,也就是枚举,最后进行对比找出最优解

(其实搜索就是暴力枚举)

话不多说,代码如下:

#include<bits/stdc++.h>
using namespace std;
int n/*集装箱*/,c/*总载重*/,ans=0;
int a[30];
void dfs(int x,int y/*目前最优解*/)
{
	if(x>n)//边界
	{
		if(ans<y)
		{
			ans=y;
		}
		return;
	}
	if(y+a[x]<=c)//其中一种情况尝试
	{
		dfs(x+1,y+a[x]);
	}
	dfs(x+1,y);//另一种情况尝试
}
int main()
{
	scanf("%d%d",&n,&c);
	for(int i=1;i<=n;i++) 
		scanf("%d",&a[i]);
	dfs(1,0);
	printf("%d",ans);
	return 0;
}

【搜索与回溯算法】迷宫问题

接下来便是搜索与回溯算法最重要的一个点:迷宫问题!!!

题目描述

设有一个N*N(2<=N<10)方格的迷宫,入口和出口分别在左上角和右上角.迷宫格子中分别放0和1,0表示可通过,1表示不能通过,入口和出口处肯定是0.迷宫走的规则如下所示:即从某点开始,有八个方向可走,前进方格中数字和为0时表示可通过,为1时表示不可通过,要另找路径.找出所有从入口(左上角)到出口(右上角)的路径(不能重复),输出路径总数,如果无法到达,则输出0.

输入

第一行输入n,表示n行n列的迷宫
接下来有n行,每行n个数,分别用1或0表示能否通过

输出

输出路径数

样例输入

3
0 0 0
0 1 1
1 0 0

样例输出

2

题解

我们仅需将每一步都试一遍,只要符合要求即可走出去

代码如下:

#include<bits/stdc++.h>
using namespace std;
int dx[8]={0,0,-1,1,-1,-1,1,1};//x坐标增量
int dy[8]={1,-1,0,0,1,-1,1,-1};//y坐标增量
int ans,n,maz[1000][1000];
void dfs(int x,int y)
{
	if(x==0&&y==n-1)
	{
		ans++;
		return;
	}
	for(int i=0;i<8;i++)//每个方向都要试一遍
	{
		int xx=x+dx[i];//我们亲切地称其为“替死鬼”
		int yy=y+dy[i];//我们亲切地称其为“替死鬼”
		if(xx>=0&&yy>=0&&xx<n&&yy<n && maz[xx][yy]==0)//判断替死鬼走的这一步有没有障碍或走出边界
		{
			maz[x][y]=1;//没有问题就走出去
			dfs(xx,yy);
			maz[x][y]=0;//回溯
		}
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			scanf("%d",&maz[i][j]);//输入
		}
	}
	dfs(0,0);
	printf("%d",ans);
	return 0;
}

【搜索与回溯算法】马的走法

题目描述

在5X5的棋盘上,给定一位置,输出马回到原点有多少种不同的方案。
注意:马走的每一步必须在棋盘上,走斜日,如下图:

输入

给定一位置,x ,y,中间有一空格隔开。

输出

输出可以回到原点的方案总数

样例输入

1 1

样例输出

61424

题解

相对于上一题,我们仅需对方向增量进行改变,因为马是走日的

代码如下:

#include<bits/stdc++.h>
using namespace std;
int sum=0,a,b,c=0;
int maz[10][10];
int dx[8]={-2,-2,-1,1,2,2,1,-1};
int dy[8]={-1,1,2,2,1,-1,-2,-2};
void dfs(int x,int y)
{
	if(x==a&&y==b&&c==1)
	{
		sum++;
		return;
	}
	c=1;
	for(int i=0;i<8;i++)
	{
		int xx=x+dx[i];
		int yy=y+dy[i];
		if(xx<=5&&yy<=5&&xx>=1&&yy>=1 && maz[xx][yy]==0)
		{
			maz[xx][yy]=1;
			dfs(xx,yy);
			maz[xx][yy]=0;
		}
	}
}
int main()
{
	scanf("%d%d",&a,&b);
	dfs(a,b);
	printf("%d",sum);
	return 0;
}

结尾

本章结束了,搜索与回溯算法还是需要熟悉一段时间的,小编会再发布一篇巩固文。

记得点赞关注加收藏,欢迎在下方评论提出问题,小编会耐心解答!

  • 60
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值