DFS深度优先算法学习
刚开始学习算法,参考大佬博客还是有很多不明白的,于是一步步解析,写下笔记记录。
大佬博客地址:
https://blog.csdn.net/fuzekun/article/details/85220468
问题描述
n个人参加某项特殊考试。
为了公平,要求任何两个认识的人不能分在同一个考场。
求是少需要分几个考场才能满足条件。
输入格式
第一行,一个整数n(1<n<100),表示参加考试的人数。
第二行,一个整数m,表示接下来有m行数据
以下m行每行的格式为:两个整数a,b,用空格分开 (1<=a,b<=n) 表示第a个人与第b个人认识。
输出格式
一行一个整数,表示最少分几个考场。
样例输入
5
8
1 2
1 3
1 4
2 3
2 4
2 5
3 4
4 5
样例输出
4
样例输入
5
10
1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5
样例输出
5
因为数据量很小可以使用回溯算法。
应用两层回溯:
第一层回溯是将考生放在不同考场里面产生的效果,比如学生3号可以放在教室1和教室2中那么放在那一个教室会产生更好的效果这是一层回溯。
第二层回溯是考生放入以前的考场还是考生自己重新用一个考场。比如考生3号可以放进教室1和教室2,也可以放进教室3。
应用简单的剪枝技巧:
现在考场的数量已经大于以前最少的考场数量了就不用在展开了。
因为题目中没有时间限制,所以可以不使用vector,使用二维数组存放边,使用二维数组存放教室中学生。
另外使用vecot中的find()总是报错所以就不使用了
使用二维数组的时间复杂度约为O(nn)因为没一个学生需要遍历之前的考场就需要遍历每个人一次1 + 2…+n - 1;
使用vector最好的情况是NlogN,这种情况对应只有一个考场,每个学生耗费logN的复杂度,NlogN,最坏的情况就会退成O(NN),对应着N个考场,每个之前的学生都需要遍历一次。
#include<stdio.h>
#include<iostream>
#include<vector>
#include<string.h>
using namespace std;
const int maxn = 100 + 5;
int room[maxn][maxn];//保存教室i中第j个学生的id
int gra[maxn][maxn];//存图
int m,n;
int res = maxn + 500;//保存答案
void solve(int id,int num)
{
//printf("%d %d\n",id,num);
if(num >= res){//剪枝
return ;
}
if(id > n){//学生的编号从1开始防止room[][] = 0不是没学生的标志
res = min(res,num);
return ;
}
for(int i = 1;i <= num;i++){//找到id是否有符合的教室
int k = 0,flag = 1;
while(room[i][k]){//查找学生教室中是否有认识的人
// printf("%d %d %d\n",id,room[i][k],gra[id][room[i][k]]);
if(gra[id][room[i][k]]){//教室里面有认识的人
//printf("冲突\n");
flag = 0;
break;
}
k++;//不要写在数组里面防止执行顺序的不对而出错
}
if(flag){ //回溯一定对应着判断
room[i][k] = id;
solve(id+1,num);
room[i][k] = 0; //第一层回溯
}
}
//重新开启一个教室
room[num+1][0] = id;
solve(id+1,num+1);
room[num+1][0] = 0;//第二层回溯
}
void init()
{
memset(room,0,sizeof(room));
}
int main()
{
init();
scanf("%d%d",&n,&m);
for(int i = 0;i < m;i++){
int a,b;
scanf("%d%d",&a,&b);
gra[a][b] = gra[b][a] = 1;
}
solve(1,0);
printf("%d\n",res);
return 0;
}
分析:
假设5个人,1,2,3,4,5 1,3,5互相认识
程序开始
输入 n=5 5个人 m=?命令数
初始 room[i][j] =0 i为房间,j为学生
输入
1 3
1 5
3 5
gra[1][3] = gra[3][1] =1
gra[1][5] = gra[5][1] =1
gra[3][5] = gra[5][3] =1
solve(id=1,num=0){ id为学生,num为房间数
room[1][0] =1
solve(id=2,num=1){
room[1][1]=2
solve(id=3,num=1){
room[2][0]=3
solve(id=4,num=2){
room[1][2]=4
solve(id=5,num=2){
room[3][0]=5
solve(id=6,num=3){
res=num=3
return
}
room[3][0]=0
}
room[1][2]=0
room[2][1]=4
solve(id=5,num=2){
room[3][0]=5
solve(id=6,num=3){
res=num=3
return
}
room[3][0]=0
}
room[2][1]=0
room[3][0]=4
solve(id=5,num=3){
3 >= 3 剪枝
return
}
room[3][0]=0
}
room[2][0]=0
}
room[1][1]=0
room[2][0]=2
solve(id=3,num=2){
room[2][1]=3
solve(id=4,num=2){
room[1][1]=4
solve(id=5,num=2){
room[3][0]=5
solve(id=6,num=3){
res =3
return
}
room[3][0]=0
}
room[1][1]=0
room[2][2]=4
solve(id=5,num=2){
room[3][0]=5
solve(id=6,num=3){
res =3
return
}
room[3][0]=0
}
room[3][0]=4
solve(id=5,num=3){
剪枝
return
}
}
room[2][1]=0
room[3][0]=3
solve(id=4,num=3){
剪枝
return
}
}
room[2][0]=0
}
room[2][0]=2
solve(id=3,num=2)
……
}
递归逻辑步骤
首先进入函数,
1判断当前的num屋子数是否大于等于已记录的屋子数res,如果符合则剪枝return
2判断当前的人id是否超过总人数,如果符合则记录当前屋子数res且return
3循环判断现在的人id在已存在的num屋子数是否有认识人,如果没有则放在相应的后面
4创建一个新屋子,将现在的人放入,并将下一个人进行判断
假设过程:
id=1的人没有房子,开设新房子num=1并放入,
递归id=2,发现num=1可以放入,
递归id=3,发现num=1有认识的人,开设新房间num=2放入
递归id=4,发现num=1可以放入
递归id=5,发现num=1,num=2有认识的人,开设新房间num=3放入
递归id=6,发现超过人数,记录下第一次得到的房间数res=num=3
回溯id=4,不放进num=1,放入num=2
递归id=5,发现num=1,num=2有认识的人,开设新房间num=3放入
递归id=6,发现房间数num=3与res相等,表示不会出现更优解,进行剪枝
回溯id=4,不放进num=1,num=2,开设新房间num=3
递归id=5,发现房间数num=3与res相等,表示不会出现更优解,进行剪枝
id=4停止
id=3停止
回溯id=2,开设新房间num=2放入
递归id=3,发现num=1有认识的人,放入num=2中
递归id=4,发现num=1可以放入
递归id=5,发现num=1,num=2有认识的人,开设新房间num=3放入
递归id=6,发现超过人数,记录下第一次得到的房间数res=num=3
回溯id=4,不放进num=1,放入num=2
递归id=5,发现num=1,num=2有认识的人,开设新房间num=3放入
递归id=6,发现房间数num=3与res相等,表示不会出现更优解,进行剪枝
回溯id=4,不放进num=1,num=2,开设新房间num=3
递归id=5,发现房间数num=3与res相等,表示不会出现更优解,进行剪枝
id=4停止
递归id=3,开设新房间num=3,发现房间数num=3与res相等,表示不会出现更优解,进行剪枝
id=3停止
id=2停止
id=1停止
细节:首先进行剪枝判断来优化程序,当id数超过总人数表示一条支路到尽头,到尽头后往前回溯上一级的另外一种可能性,同样到尽头后再回溯,直到顶级结束
所有的回溯以开设新房间为最差方式结束。
思想核心:首先选择一个起点,先沿着一条路走到尽头,然后回溯上一步走另外一种可能,所有可能性走完后继续回溯上级再走上级的另外可能
总体的步骤图(差不多能看。。):
①
②
③
④
⑤
⑥
⑦
(回到起点结束)
DFS深度优先算法学习的更多相关文章
- 算法学习之BFS、DFS入门
算法学习之BFS.DFS入门 0x1 问题描述 迷宫的最短路径 给定一个大小为N*M的迷宫.迷宫由通道和墙壁组成,每一步可以向相邻的上下左右四格的通道移动.请求出从起点到终点所需的最小步数.如果不能到 ...
- 广度优先算法(BFS)与深度优先算法(DFS)
一.广度优先算法BFS(Breadth First Search) 基本实现思想 (1)顶点v入队列. (2)当队列非空时则继续执行,否则算法结束. (3)出队列取得队头顶点v: (4)查找顶点v的所 ...
- 回溯算法 DFS深度优先搜索 (递归与非递归实现)
回溯法是一种选优搜索法(试探法),被称为通用的解题方法,这种方法适用于解一些组合数相当大的问题.通过剪枝(约束+限界)可以大幅减少解决问题的计算量(搜索量). 基本思想 将n元问题P的状态空间E表示成 ...
- [算法总结]DFS(深度优先搜索)
目录 一.关于DFS 1. 什么是DFS 2. DFS的搜索方式 二.DFS的具体实现 三.剪枝 1. 顺序性剪枝 2. 重复性剪枝 3. 可行性剪枝 4. 最优性剪枝 5. 记忆化剪枝 四.练习 一 ...
- [ACM训练] 算法初级 之 搜索算法 之 深度优先算法DFS (POJ 2251+2488+3083+3009+1321)
对于深度优先算法,第一个直观的想法是只要是要求输出最短情况的详细步骤的题目基本上都要使用深度优先来解决.比较常见的题目类型比如寻路等,可以结合相关的经典算法进行分析. 常用步骤: 第一道题目:Dung ...
- Java与算法之(5) - 老鼠走迷宫(深度优先算法)
小老鼠走进了格子迷宫,如何能绕过猫并以最短的路线吃到奶酪呢? 注意只能上下左右移动,不能斜着移动. 在解决迷宫问题上,深度优先算法的思路是沿着一条路一直走,遇到障碍或走出边界再返回尝试别的路径. 首先 ...
- Kosaraju算法学习
Kosaraju 算法学习 序 这星期捣鼓了一个新的算法--Kosaraju算法 今天分享给大家 简介 Kosaraju算法,其实与tarjan算法差不多.但是码量较小,容易记忆.其时间复杂度与tar ...
- dijkstra算法学习
dijkstra算法学习 一.最短路径 单源最短路径:计算源点到其他各顶点的最短路径的长度 全局最短路径:图中任意两点的最短路径 Dijkstra.Bellman-Ford.SPFA求单源最短路径 F ...
- (原创)不过如此的 DFS 深度优先遍历
DFS 深度优先遍历 DFS算法用于遍历图结构,旨在遍历每一个结点,顾名思义,这种方法把遍历的重点放在深度上,什么意思呢?就是在访问过的结点做标记的前提下,一条路走到天黑,我们都知道当每一个结点都有很 ...
随机推荐
- [ZJOI2006]物流运输trans
Description 物流公司要把一批货物从码头A运到码头B.由于货物量比较大,需要n天才能运完.货物运输过程中一般要转停好几个码头.物流公司通常会设计一条固定的运输路线,以便对整个运输过程实施严格 ...
- Anrlr4 生成C++版本的语法解析器
一. 写在前面 我最早是在2005年,首次在实际开发中实现语法解析器,当时调研了Yacc&Lex,觉得风格不是太好,关键当时yacc对多线程也支持的不太好,接着就又学习了Bison&F ...
- Spring Boot2 系列教程(十三)Spring Boot 中的全局异常处理
在 Spring Boot 项目中 ,异常统一处理,可以使用 Spring 中 @ControllerAdvice 来统一处理,也可以自己来定义异常处理方案.Spring Boot 中,对异常的处理有 ...
- 阿里云 RDS 数据库又发 CPU 近 100% 的“芯脏病”
最近云界发生了2件事,一件是大事,一件是小事,大事是阿里云与微软合作推出了开放应用模型 Open Application Model(OAM),小事是由于微软 SQL Server 在阿里云上水土不服 ...
- PMP(第六版)中的控制账户、规划包、工作包
PMP(第六版)中的控制账户.规划包.工作包 控制账户是一个管理控制点,在该控制点上,把范围.预算和进度加以整合,并与挣值比较,以测量绩效.控制账户拥有2个或以上的工作包,但每个工作包只与一个控制账户 ...
- 前端知识点总结——jQuery(上)
1.什么是jQuery jQuery: 第三方的极简化的DOM操作的函数库第三方: 下载极简化: 是DOM操作的终极简化: 1. DOM: 增删改查2. 事件绑定:3. 动画效果:4. Ajax DO ...
- JS循环+循环嵌套+经典例题+图形题
首先,了解一下循环嵌套的特点:外层循环转一次,内层循环转一圈. 在上一篇随笔中详细介绍了JS中的分支结构和循环结构,我们来简单的回顾一下For循环结构: 1.for循环有三个表达式,分别为: ①定义循 ...
- 剑指Offer(十九)——顺时针打印矩阵
题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字. 例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 ...
- POJ 3020 Antenna Placement(二分图 匈牙利算法)
题目网址: http://poj.org/problem?id=3020 题意: 用椭圆形去覆盖给出所有环(即图上的小圆点),有两种类型的椭圆形,左右朝向和上下朝向的,一个椭圆形最多可以覆盖相邻的两 ...
- python中如何通过报错信息定位问题(异常传播轨迹)
class SelfException(Exception): pass def main(): firstMethod() def firstMethod(): secondMethod() def ...