21.1.23 回溯算法 LeetCode52-n皇后

本文介绍了回溯算法的基本概念,将其比喻为按树状图展开的深度优先搜索策略,并列举了典型的应用场景,如装载问题、0-1背包问题等。重点讨论了N皇后问题,给出了两种不同的C语言实现模板代码,详细解释了代码逻辑,展示如何通过回溯法求解N皇后问题的解法数量。
摘要由CSDN通过智能技术生成

(记录一下道阻且长的学习之路)

回溯算法

回溯算法是一种将问题的的解空间按树状图形式展开,在寻找问题的解时使用深度优先搜索策略进行遍历(暂时也不懂啥意思),并记录寻找可行解或最优解。
回溯算法一般会应用于地图路线之类的问题的解决吧

看了一下大概有以下几类

(1)装载问题 (2)0-1背包问题 (3)旅行售货员问题 (4)八皇后问题 (5)迷宫问题 (6)图的m着色问题

学习链接是https://blog.csdn.net/weiyuefei/article/details/79316653

LeetCode 52 N-Queens II(N皇后问题)

模版代码

来源:https://blog.csdn.net/Szujr/article/details/103737183?utm_source=app
(侵权联系删除)

//
//  T2 N皇后问题.c
//  c 191219
//
//  Copyright © 2019 JaYLove0589. All rights reserved.
//

#include <stdio.h>
#include <string.h>
#pragma warning (disable:4996)
int getMethod(const int n);
int checkPoint(int* column, const int n);

int main() {

    const int MAX = 10;//说明N最大为10
    const int END = 0;//说明输入0表示程序结束

    int N;
    while (scanf("%d", &N)) {
        if (N > MAX || N < 0) {
            return -1;
        }
        else if (N == END) {
            return 0;
        }
        int method = getMethod(N);

        printf("%d", method);
        printf("\n");
    }
    return 0;
}

int getMethod(const int n) 
{
    int column[9 + 1];
    //    column[1]~column[n]存储n个皇后的纵坐标,其下标表示皇后的横坐标,column[0]存储皇后的总共摆法
    memset(column, 0, (n + 1) * sizeof(int));//column数组置零

    int method = checkPoint(column, n);//返回总共的摆法
    return method;
}

int checkPoint(int* pcolumn, const int n) {//row表示当前要查找的点的行数(1~n)

    static int row = 1;//查找点的起始行数为第一行
    if (pcolumn[0] == 0 && pcolumn[1] == 0) 
    {//若pcolumn数组被置零,说明重新开始查找,将row的值初始化为1
        row = 1;//
    }
    int flag = 0;//标志变量,值为1表示找到的皇后的点不满足条件

    for (int column1 = 1; column1 <= n; column1++) 
    {//从row行的第1列开始寻找点,直到该行的最后一列
        for (int row1 = 1; row1 < row; row1++) 
        {//依次与已找到的皇后点比较,若有冲突则flag=1,且continue列数
            if (pcolumn[row1] == column1 || row1 - pcolumn[row1] == row - column1 || row1 + pcolumn[row1] == row + column1) {//判断该行上的点(row,column1)是否与已有的皇后点处在同一列或同一左斜线或同一右斜线
                flag = 1;
                break;
            }
        }
        if (flag == 1) 
        {
            flag = 0;
            continue;
        }
        pcolumn[row] = column1;//若满足条件,记录该行皇后的列数(纵坐标)
        row++;//因为已找到,所以进入下一行
        if (row - 1 == n) 
        {//若找齐所有皇后的点
            pcolumn[0]++;//用pcolumn[0]表示摆法的种数,种数+1
            row = row - 2;//row回到倒数第2行
            return pcolumn[0];
        }
        else 
        {
            checkPoint(pcolumn, n);//递归算法,在row行开始寻找点
        }
    }
    row--;//若该行所有列数都找完,都找不到满足条件的点,则回到上一行(上一层循环)
    return pcolumn[0];//返回当前已找到的所有摆法
}

//思路总结:
//已知棋盘共nxn个格子,现以(1,1)为起点,(n,n)为终点。依次寻找满足条件的N个点。
//(0)若找到且已找到的点的数量为N,皇后摆法的个数加一,且返回倒数2层循环;并延续寻找,直到找到下一个满足条件的点,若没找齐返回摆法个数。
//(1)若走到尽头仍不能找齐最后一个棋子(n-1个满足条件的棋子点已找到),则返回倒数第2层循环;并延续寻找倒数第2个棋子的位置,直到找到下一个满足倒数第2个棋子摆放要求的点。—>(2)
//(2)若找到,则进入下一层循环,开始寻找下一层循环的点。若倒数第二走到尽头仍不能满足条件,则返回倒数第3层循环;并延续寻找倒数第三个棋子的点位置,直到找到下一个满足倒数第三个棋子摆放条件的点。—>(3)
//(3)若倒数第三个棋子走到尽头仍没找到,返回倒数第四个循环……
//(…)……
//(n)若第1个棋子走到尽头,仍没找到,则循环结束,返回摆法个数。


自己琢磨的(和上面的差不多)

#include <stdio.h>
#include <stdlib.h>
#pragma warning (disable:4996)
int queencol[10];
int method = 0;
void init(int* a)
{
	for (int i = 0; i < 10; i++)
		queencol[i] = 0;
}
int check(int n)
{
	static int row = 1;//start_row
	int flag = 0;
	if (method == 0 && queencol[1] == 0)
		row = 1;

	for (int i = 1; i <= n; i++)//from col=1--col=n 
	{
		for (int j = 1; j < row; j++)// 
		{
			if (queencol[j] == i)//该列有皇后 
			{
				flag = 1;
				break;
			}
			if (j - queencol[j] == row - i || j + queencol[j] == row + i)//对角线上有皇后 
			{
				flag = 1;
				break;
			}
		}
		if (flag == 1)//can't satisfy,look for next
		{
			flag = 0;
			continue;
		}
		//satusfied,no continue and pass,note down this place
		queencol[row] = i;
		row++;//next col 
		if (row == n + 1)//all queens placed
		{
			method++;
			row=row-2;//return last 2
			return method;
		}
		else//not finshed,place next queen until all placed
		{
			check(n);
		}
	}
	row--;//return last 
	return method;
}

int totalNQueens(int n)
{
	method = 0;
	init(queencol);
	check(n);
	return method;
}
int main()
{
	int in;
	scanf("%d", &in);
	printf("%d",totalNQueens(in));
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值