深度优先搜索(DFS)

在这里插入图片描述

一、关于DFS的一些小概念

DFS可谓是“不撞南墙,不回头”。就像走迷宫一样,选择一条路一直走下去,当撞南墙了,才返回分叉口去试下一条路。
有两个概念需要提前明晰一下:
1、状态:状态一般是指客观现场信息的描述,通常用T表示。一般要注意是指当前状态,用T0表示初始状态,Tn表示终止状态。
2、产生式系统。状态依据产生式规则,转移至另一个状态。它主要体现状态的表示,新状态产生的规则,状态转移三大功能。

重点理解
1、DFS实际上是利用递归进行的暴力搜索,因此,写DFS之前我们要弄清楚枚举对象,这点很关键,枚举对象也必然是DFS参数之一。其次要弄清楚该枚举对象的初始状态,目标状态。
2、 DFS适用于此类题目:给定初始状态和目标状态,要判断从初始状态到目标状态是否有解

二、典型例题解析

void dfs(int k)
{
	if(到达终点或者目的地)
	{
		输出问题解或者解得方案数+1}
	for(int i = 0;i<="可扩展状态总数";i++)
	{
		按照规则,产生新的状态;
		if(判断新状态是否合法)
		{
			 保存合法结果;
			 dfs(k+1);
		}
	}
}
int main()
{
	.....
	dfs(k);
	return 0;
}

例题1、体积
【问题描述】
给出 n 件物品,每件物品有一个体积 V i ,求从中取出若干件物品能够组成的不同的体积和有多少种可能。
【输入格式】
第 1 行 1 个正整数,表示 n。
第 2 行 n 个正整数,表示 V i ,每两个数之间用一个空格隔开。
【输出格式】
一行一个数,表示不同的体积和有多少种可能。
【输入样例】
3
1 3 4
【输出样例】
6
【数据规模】
对于 30% 的数据满足:n≤5,V i ≤10。
对于 60% 的数据满足:n≤10,V i ≤20。
对于 100% 的数据满足:n≤20,1≤V i ≤50。
【问题分析】
在这里插入图片描述
[视频讲解]

#include<iostream>
#include<cstdio>
using namespace std;
const int N = 21;
int v[N];
bool hash[1001];
int n;
void dfs(int index,int sum)
{
    if(index==n+1)//当准备处理n+1个元素时,说明前n个已经处理完毕;也可以写成index>n
    {
        hash[sum]=true;
        return ;
    }

    dfs(index +1,sum+v[index]);//枚举取第index件物品
    dfs(index+1,sum);//枚举不取第index件物品
}

int main()
{
    cin >> n;
    for(int i=1;i <= n;i++)
    {
        cin >> v[i];
    }
    dfs(1,0);
    int ans = 0;
    for(int i = 1;i <1001;i++)//数据规模中明确最多20个物品,每个物品最大体积50,所以枚举体积最大到1000
    {
        if(hash[i]) ans++;
    }
    cout << ans;
}

例题二:瓷砖

描述:
在一个W * h的矩形广场上,每一块1 * 1的地面都铺设了红色或黑色瓷砖。小林同学站在某一块黑色瓷砖上,他可以从此处出发,移动到上下左右四个相邻的且是黑色的瓷砖上。现在他想知道,通过重复上述移动所能经过的黑色瓷砖数。
输入:
第一行为h、w,2<=w、h<=50,之间有一个空格隔开。
以下为一个w行h列的二维字符矩阵,每个字符为“.” “#” “@”分别表示该位置为黑色瓷砖、红色瓷砖、小林初始位置。
输出:
输出一行一个整数,表示小林从出发位置可以经过的黑色瓷砖数量。
输入实例:
11 9
.#…
.#.#######.
.#.#…#.
.#.#.###.#.
.#.#…@#.#.
.#.#####.#.
.#…#.
.#########.

输出实例:
59

[视频讲解]
例题三:背包问题

背包问题(pack,1s,256M)
【问题描述】
小明就要去春游了。妈妈给他买了很多好吃的。小明想把这些吃的都放进他的书包,但他很快发现,妈妈买的东西实在太多了,他必须放弃一些,但又希望能带尽可能多的好吃的。举算法解决一些实际问题。
已知小明的书包最多可以装入总重量为 s 的物品,同时也知道小明妈妈给他买的每样东西的重量。请从这些好吃的中选出若干装入小明的书包中,使得装入物品的总重量正好为 s。找到任意一组解输出即可。
【输入数据】
第 1 行包含两个正整数 n(1≤n≤100)和 s(1≤s≤10 000),分别代表有 n 件物品和书包的最大承重 s;
第 2 行包含 n 个正整数,代表每件物品的重量 W i (1≤W i ≤1 000)。同行的两个数字之间用一个空格隔开。
【输出数据】
一行包含有若干用一个空格隔开的正整数,代表被放入书包的若干物品各自的重量。若无可行解,则输出“No Answer !”。
【输入样例】
8 14
1 3 2 5 9 4 7 6
【输出样例】
1 3 4 6
【输入样例】
3 12
2 8 5
【输出样例】
No Answer!

【问题分析】
本题是最简单的“0-1 背包问题”。只要从第一件物品开始,考虑取和不取两种情况,进行递归深搜,一旦发现装入物品的总重量等于背包的容量,就输出答案。
此算法的时间复杂度为O(2n ),对于 n=100,显然会超时。我们将在后面专门讨论解决 0-1 背包问题的其他算法。

[视频讲解]

练习题目:

1、最大黑区域
-----视频讲解

2、分成两组
-----视频讲解

3、邻之差为K
视频讲解

4、验证四色原理
视频讲解
类似题目:图的m着色问题

5、图的遍历
视频讲解

6、生日
视频讲解

7、门票
视频讲解

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信奥教练Andy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值