不撞南墙不回头----------深度优先搜索

深度优先搜索算法(Depth First Search,简称DFS):一种用于遍历或搜索树或图的算法。 沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过或者在搜寻时结点不满足条件,搜索将回溯到发现节点v的那条边的起始节点。整个进程反复进行直到所有节点都被访问为止。属于盲目搜索,最糟糕的情况算法时间复杂度为O(!n)。

深度优先模板

void dfs(int step)
{
   判断边界
   尝试扁历每一种可能for(i=0;i<n;i++)
{
    继续下一步dfs(step+1)
  
}
返回
}

推荐

啊哈算法的扑克牌的放置问题

首先的三张扑克牌的放置由1.2 3的顺序表依次放置

放置很简单只需要一个for循环

for(int i=1;i<=n;i++)
	a[step]=i;
	//将i号扑克牌放到第step个盒子中

在后我们需要考虑扑克牌是否还有剩这时候我们用一个数组来标记是否手中还有扑克牌

for(int i=1;i<=n;i++){
	if(book[i]==0){   
	//说明i号扑克牌还在手里,需要放入step号盒子
	a[step]=i;
	//将i号扑克牌放到第step个盒子中
	book[i]=1;
	//此时i号扑克牌已经被使用
		}
	}

为了嫌弃麻烦我们不用每一次的扑克牌是否在手中都要写上面这一段的代码我们引入一个函数

void  dfs(int step){ //此时在第step盒子面前,需要往里面放第i张扑克牌
	for(int i=1;i<=n;i++){
	if(book[i]==0){   
	//说明i号扑克牌还在手里,需要放入step号盒子
	a[step]=i;
	//将i号扑克牌放到第step个盒子中
	book[i]=1;
	//此时i号扑克牌已经被使用
		}
	}
}

但是我们每次的扑克牌都不是判断一次那岂不是每次都要拿一手新的扑克这时候我们永递归回收扑克牌

void  dfs(int step){ //此时在第step盒子面前,需要往里面放第i张扑克牌
 for(int i=1;i<=n;i++){
	if(book[i]==0){   
	//说明i号扑克牌还在手里,需要放入step号盒子
	a[step]=i;//将i号扑克牌放到第step个盒子中
	book[i]=1;//此时i号扑克牌已经被使用
		
	dfs(step+1);
	/*注意这里是自己调用自己,表示此时走到了第step+1个盒子面前*/		
	book[i]=0;
	/*book[i]=0表示dfs调用结束了,换句话说就是扑克牌已经全部放完了
	  需要按照顺序将扑克牌收回,重新放,也就是前面所说的
	 */
		}
	}
}

这就是最基本的dfs问题一直遍历到底

推荐题目

LeetCode  77 

(全排列问题)

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

示例 1:

输入:n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]
示例 2:

输入:n = 1, k = 1
输出:[[1]]
 

提示:

1 <= n <= 20
1 <= k <= n

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/combinations
 

 

int* path;
int pathTop;
int** ans;
int ansTop;

void backtracking(int n, int k,int startIndex) {
    //当path中元素个数为k个时,我们需要将path数组放入ans二维数组中
    if(pathTop == k) {
        //path数组为我们动态申请,若直接将其地址放入二维数组,path数组中的值会随着我们回溯而逐渐变化
        //因此创建新的数组存储path中的值
        int* temp = (int*)malloc(sizeof(int) * k);
        int i;
        for(i = 0; i < k; i++) {
            temp[i] = path[i];
        }
        ans[ansTop++] = temp;
        return ;
    }

    int j;
    for(j = startIndex; j <=n ;j++) {
        //将当前结点放入path数组
        path[pathTop++] = j;
        //进行递归
        backtracking(n, k, j + 1);
        //进行回溯,将数组最上层结点弹出
        pathTop--;
    }
}

int** combine(int n, int k, int* returnSize, int** returnColumnSizes){
    //path数组存储符合条件的结果
    path = (int*)malloc(sizeof(int) * k);
    //ans二维数组存储符合条件的结果数组的集合。(数组足够大,避免极端情况)
    ans = (int**)malloc(sizeof(int*) * 10000);
    pathTop = ansTop = 0;

    //回溯算法
    backtracking(n, k, 1);
    //最后的返回大小为ans数组大小
    *returnSize = ansTop;
    //returnColumnSizes数组存储ans二维数组对应下标中一维数组的长度(都为k)
    *returnColumnSizes = (int*)malloc(sizeof(int) *(*returnSize));
    int i;
    for(i = 0; i < *returnSize; i++) {
        (*returnColumnSizes)[i] = k;
    }
    //返回ans二维数组
    return ans;
}

// 剪枝:
int* path;
int pathTop;
int** ans;
int ansTop;

void backtracking(int n, int k,int startIndex) {
    //当path中元素个数为k个时,我们需要将path数组放入ans二维数组中
    if(pathTop == k) {
        //path数组为我们动态申请,若直接将其地址放入二维数组,path数组中的值会随着我们回溯而逐渐变化
        //因此创建新的数组存储path中的值
        int* temp = (int*)malloc(sizeof(int) * k);
        int i;
        for(i = 0; i < k; i++) {
            temp[i] = path[i];
        }
        ans[ansTop++] = temp;
        return ;
    }

    int j;
    for(j = startIndex; j <= n- (k - pathTop) + 1;j++) {
        //将当前结点放入path数组
        path[pathTop++] = j;
        //进行递归
        backtracking(n, k, j + 1);
        //进行回溯,将数组最上层结点弹出
        pathTop--;
    }
}

int** combine(int n, int k, int* returnSize, int** returnColumnSizes){
    //path数组存储符合条件的结果
    path = (int*)malloc(sizeof(int) * k);
    //ans二维数组存储符合条件的结果数组的集合。(数组足够大,避免极端情况)
    ans = (int**)malloc(sizeof(int*) * 10000);
    pathTop = ansTop = 0;

    //回溯算法
    backtracking(n, k, 1);
    //最后的返回大小为ans数组大小
    *returnSize = ansTop;
    //returnColumnSizes数组存储ans二维数组对应下标中一维数组的长度(都为k)
    *returnColumnSizes = (int*)malloc(sizeof(int) *(*returnSize));
    int i;
    for(i = 0; i < *returnSize; i++) {
        (*returnColumnSizes)[i] = k;
    }
    //返回ans二维数组
    return ans;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值