回溯算法

回溯算法定义

       回溯法是一种系统搜索问题解空间的方法。为了实现回溯,需要给问题定义一个解空间。说到底它是一种搜索算法。只是这里的搜索是在一个叫做解空间的地方搜索。要实现回溯,需要两点1搜索,2解空间。
       先看什么是解空间。就是形如数组的一个向量[a1,a2,…,an]。这个向量的每个元素都是问题的部分解,只有当这个数组的每一个元素都填满(得到全部解)的时候,才表明这个问题得到了解答。
       再看搜索。最简单的就是for循环,上面的向量有n个维度,因此就是n个for循环。但是如果n是100?n是100000?那么如何回溯?因此我们需要一种全新的书写回溯的方法。形如:

void backtrack(int i,int n,other parameters)
{
	if (some condition) {
		// 剪枝
		return;
	}
	if ( i == n) {
		//get one answer
		record answer;
		return;
	}
	//下面的意思是求解空间第i个位置上的下一个解
	for (next ans in position i of solution space) {
		push(ans);
		backtrack(i+1,n,other parameters);
		pop(ans);
	}
}

举例

       n皇后(LeeCode 51题)

       n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击,同一行,同一列或者对角线上的皇后可互相攻击(正对角线上行列之和为常数,负对角线上行列之差为常数)。每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。示例:

	输入: 4
	输出: [
	 [".Q..",  // 解法 1
	  "...Q",
	  "Q...",	
	  "..Q."],
	
	 ["..Q.",  // 解法 2
	  "Q...",
	  "...Q",
	  ".Q.."]
	]
	解释: 4 皇后问题存在两个不同的解法。

在这里插入图片描述

#define MAX_NUM 2000
int valid(int *solution, int row)
{
    for (int i = 0; i < row - 1; i++) {
        if ((solution[i] == solution[row-1]) || 
            (i + solution[i]) == (row-1 + solution[row-1]) ||
            (i - solution[i]) == (row-1 - solution[row-1])) {
            return 0;
        }
    }
    return 1;
}

void traceBack(int n, int row, int *solution, int **allSolu, int *soluNum)
{    
	/*剪枝*/
    if (!valid(solution, row)) {
        return;
    }
   
   /*获得一个解*/ 
    if (row == n) {
        int *tmp = malloc(sizeof(int) * n);
        memcpy(tmp, solution, sizeof(int) * n);
        allSolu[*soluNum] = tmp;
        (*soluNum)++;
        return;
    }
    
    /*遍历求解空间第i个位置上的下一个解*/
    for (int i = 0; i < n; i++) {
        solution[row] = i;
        traceBack(n, row + 1, solution, allSolu, soluNum);
    }
}

char *** solveNQueens(int n, int* returnSize, int** returnColumnSizes){
    int *solution = malloc(sizeof(int) * n);
    int **allSolu = malloc(sizeof(int*) * MAX_NUM);
    int soluNum;
    char *** rtn;
    traceBack(n, 0, solution, allSolu, &soluNum);
    rtn = malloc(sizeof(char**) * soluNum);
    for (int i = 0; i < soluNum; i++) {
        rtn[i] = malloc(sizeof(char*) * n);
        for (int j = 0; j < n; j++) {
            rtn[i][j] = malloc(sizeof(char) * (n + 1));
            memset(&rtn[i][j][0], '.', n);
            rtn[i][j][allSolu[i][j]] = 'Q';
            rtn[i][j][n] = 0;                   
        }
    }
    *returnSize = soluNum;
    *returnColumnSizes = malloc(sizeof(int) * soluNum);
    for (int j = 0; j< soluNum; j++){
        (*returnColumnSizes)[j] = n;
    } 
    return rtn;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值