心得体会
第一天的时候发现自习八小时真的想④,到现在第三天觉得八小时还不够我用的。作为零基础学算法的人,真的每次看到一个新的问题模型,一个新的算法都要理解好久,真的痛苦。我也不想每天就只写那两道题可是我完全理解那两道题就花了三四个小时了,然后自己上手写代码还有这样那样的问题改来改去又是一两个小时。
学习内容
bfs广度搜索基础内容
虽然都是搜索方法,虽然都是比较暴力的方法,但是发现大佬们解释起来都还是比较抽象的,这里还涉及到了队列的内容(学算法之前一定要看一些数据结构的内容啊,不要像我一样半路出家学算法,结果看到不懂的狂补数据结构)
自然数的拆分
这里(经过师傅的指导我成功学会直接放链接)
思路
这道题就是,一眼深度搜索,实际上手操作的时候发现会有部分输出数据是重复的。
我们可以根据题意,给出一个比较小的输入数据作为例子画出树状图,然后进行“剪枝”,从而避免这个重复。
我用来剪枝的条件是“开始数字”和“剩余需要的和”
通过案例来看,题目给出的n实际上是一个集合,这个是一个问题模型:在一个集合里面 使用有限个的元素 相加成为一个要求的值(组合问题),根据这个问题模型,得到剪枝条件(需要更详细的思路的话可以在站内搜索 回溯的组合问题 )
ok那么处理完重复问题,就剩下输出问题了,我刚开始非常贪懒想着把输出功能写进搜索函数,后来发现以我的技术力没办法实现,看了一下大佬的题解之后发现大家都分开写,用的思路是“搜索一路就记一路”,给出一个数组记录每一步的数据,当遇到出口条件的时候就调用输出函数直接输出(所以这里增加了一个变量,我称之为“选择步数”,同时也作为我们用于记录的数组的下标)
代码
#include<stdio.h>
int n,m,a[10];//自然数 选择次数 集合
void prin(int x)
{
for(int i=0;i<x;i++)
{
if(i==0)
printf("%d",a[i]);
else
printf("+%d",a[i]);
}
printf("\n");
}
void dfs(int snum,int x,int times) //开始数字 缺少的总和 选择步数
{
if(snum==n)
return ;
if(x==0)
{
prin(times);
return ;
}
for(int i=snum;i<=x;i++)
{
a[times]=i;
dfs(i,x-i,times+1);
}
}
int main()
{
scanf("%d",&n);
dfs(1,n,0);
}
(代码是早上打的,博客是今晚写的,我都已经快看不懂我在写什么了,写代码一定要写注释啊)
八皇后问题(的变形)
理解
因为我发现了一个写的非常好的思路和图解(这里),所以下面就只讲个人理解
对于八皇后问题,首先他是一个有网格图的问题,但是有比较多的限制条件,(对于没做过多少题的我来说 没看题解之前不会想到说用 多个一维数组 来模拟 具现为二维数组上的判断条件)
所以意味着这道题有多个维度的“标记”,同时这题和上一道题很像啊都使用了回溯,但是条件一多对回溯的处理也比较麻烦
代码
#include<stdio.h>
//行 列 上对角 下对角
int place[20];//行 第i行的皇后放在place[i]列
int a[20],b[50],c[50];//列 上对角线行+列 下对角线行-列+7
int n;//nxn棋盘,n皇后
int cnt;//方法数
void prin(int m)//这里n是充当数组下标的作用,但是为了方便理解 我的n是从1开始,也就是:第1行的皇后放在place[0]列
//所以判断出口的时候,比如说我们要放八个皇后,则当x==n+1也就是9我们就回溯
{
if(cnt<=3)
{
for(int i=0;i<m-1;i++)
printf("%d ",place[i]);
printf("\n");
}
}
void queen(int x)
{
if(x==n+1)
{
cnt++;
prin(x);
return ;
}
//进入判断部分,这里我们随着递归层数的增加,行是逐渐确定的,行确定之后就找列
//列确定了之后,根据前面的规则我们也可以确定这个格子所在的对角线在哪里,
//所以我们是判断这条对角线能不能站,而不是去遍历对角线数组确定没有标记的对角线
for(int i=0;i<n;i++)
{
if(a[i+1]==0&&b[x+i+1]==0&&c[x-i+8]==0)
{
place[x-1]=i+1;
a[i+1]=1;
b[x+i+1]=1;
c[x-i+8]=1;
queen(x+1);
a[i+1]=0;
b[x+i+1]=0;
c[x-i+8]=0;
}
}
return ;
}
int main()
{
scanf("%d",&n);
queen(1);
printf("%d",cnt);
}
今日总结
理解了剪枝是dfs 的优化方法
对于需要输出流程的dfs问题可以使用数组之类的,“搜索一步记录一步”,然后输出
回溯和dfs深度搜索是同一个东西吗 不是的话它们有什么区别
(写这段的时候是写总结的第二天:回溯和dfs不同,但是现在可以使用dfs的问题模型,对数据的处理基本都需要打标记,所以一般都把回溯叫成dfs,但是回溯的打标记方法和dfs的打标记方法不太一样:回溯的打标记就像是只在单一或者几条“树枝”上标记,而dfs的打标记是整棵树都标记)