N クイーンズ問題 - バックトラッキング法 - C 言語

N クイーン問題とバックトラック法についての理解に関しては、個人的に次のビデオをお勧めします:アルゴリズムとデータ構造、8 クイーンを解くためのバックトラック、最も古典的な再帰問題コンピューター サイエンスの古典 1848 年に国際的なチェス プレーヤー、マックス ベセルによって提起された問題の 1 つ。8 クイーン問題は、8 × 8 のチェス盤に 8 つのクイーンを配置して、互いに攻撃できないようにすることです. 2 つのクイーンを同じ行、列、または斜めに配置することはできません. 配置方法、特定の配置方法配置方法ごとに。https://www.bilibili.com/video/BV1ZK411K7A8?share_source=copy_web

ビデオのコードは C++ で書かれています. 私は組み込みの経験が豊富なので、C の使用に慣れています.

C 言語コードは次のとおりです。

/* N皇后问题 */

#include <stdio.h>

#include <stdlib.h>



#define N 100 //宏定义最大的N



int attack[N][N];

char queen[N][N];

int cnt;

void init(int n);//初始化attack和queen数组

void print(int n);//打印符合要求的摆法

void print_ack(int n);//测试update_ack函数编写是否正确

void copy(int object[N][N],int target[N][N],int n);//将对象数组保存给目标数组

void update_ack(int x,int y,int n);//摆放queen后更新attack数组,将进queen攻路线上的值标为1

void backtrack(int row,int n);//回溯法 递归调用



int main(int argc, char const *argv[])

{

    int n;

    puts("Please input the N of queen:");

    scanf("%d",&n);//计算nXn的皇后问题

    init(n);//初始化attack和queen数组

    backtrack(0,n);//从第0行开始摆放queen

    printf("The number of required placement method =%d\n",cnt);

    system("pause");

    return 0;

}

void backtrack(int row,int n)

{

    if(row==n)//递归执行到摆放完所有行的结束条件

    {

        cnt++;

        print(n);

        return ;

    }

    int col;

    for(col=0;col<n;col++)

    {

        if(attack[row][col]==0)//判断该位置是能够放置queen

        {

            int tem[N][N];//保存当前的attack数组内容,便于回溯

            copy(attack,tem,n);//遍历交换

            queen[row][col]='Q';//该位置放置queen

            update_ack(row,col,n);//放置完后将棋盘上queen的进攻路线全部标为1

            backtrack(row+1,n);//行数+1,递归回到函数头部重复判断

            //递归结束才会执行下面的语句

            copy(tem,attack,n);//将之前保存的temp返还给attack

            queen[row][col]='.';//将标记的Q改回.

    }

}

}



void init(int n)//初始化attack和queen数组

{

    int i,j;

    for(i=0;i<n;i++)//对二维数组遍历

        for(j=0;j<n;j++)

            {

                attack[i][j]=0;

                queen[i][j]='.';

            }

}



void print(int n)//打印符合要求的摆法

{

    int i,j;

    printf("cnt=%d\n",cnt);

    for(i=0;i<n;i++)

    {

        for(j=0;j<n;j++)

            {

                printf("%c\t",queen[i][j]);

            }

            printf("\n");

    }

    printf("\n");

}

void print_ack(int n)//测试update_ack函数编写是否正确

{

    int i,j;

    for(i=0;i<n;i++)//对二维数组遍历

    {

        for(j=0;j<n;j++)

            {

                printf("%d\t",attack[i][j]);

            }

            printf("\n");//每打印出n个换行

    }

}

void copy(int object[N][N],int target[N][N],int n)//将对象数组保存给目标数组

{

    int i,j;

    for(i=0;i<n;i++)

    {

        for(j=0;j<n;j++)

            {

               target[i][j]=object[i][j];

            }

           

    }

 /*    for(i=0;i<n;i++)

    {

        for(j=0;j<n;j++)

            {

                printf("%d\t",tem[i][j]);

            }

            printf("\n");

    } */

}

void update_ack(int x,int y,int n)

{

    int i,j,nx,ny;

    int dx[8]={-1,0,1,-1,  1,-1,0,1};//dx,dy的八对数 分别对应

    int dy[8]={-1,-1,-1,0, 0, 1, 1,1 };//左上,上,右上,左,右,左下,下,右下,八个方向

    attack[x][y]=1;

    for(i=1;i<n;i++)

    {

        for(j=0;j<8;j++)

        {

            nx=x+i*dx[j];

            ny=y+i*dy[j];

            if(nx>=0 && nx<n && ny>=0 && ny<n )//nx,ny判断是否在棋盘内,满足才将对应的位标记

            {

                attack[nx][ny]=1;

            }

        }

       

    }

   // print_ack(n);测试代码

   

}

(N は自由に選択できます。100 より大きい場合は、マクロ定義 #define N 100 を変更する必要があります)

コードを実行した結果:

このブログが役に立った場合は、離れる前に「いいね!」してください。

おすすめ

転載: blog.csdn.net/weixin_44322104/article/details/124278434