关于使用啰嗦代码瞎混到ac的n皇后问题

  • 题目地址:ACwing-n皇后

  • 关于思路:

    • 题目概述:n−皇后问题是指将 n 个皇后放在 n×n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。
      现在给定整数 n,请你输出所有的满足条件的棋子摆法。
    • 首先了解题意:
      1.n×n 的国际象棋棋盘上,可以使用一个二维数组来表示棋盘方阵。二维数组中每个元素的两个下标来表示该元素在棋盘上的坐标(x,y)。
      2.关键词在于“任意两个皇后都不能处于同一行、同一列或同一斜线上”,即每次落子(摆放皇后),落子坐标(x,y)要满足“不与之前已摆放的皇后坐标处于同一行、同一列或同一斜线上”的条件
      换句话说“每一行每一列每一个斜线上只能有一颗唯一的棋子”。
    • 思路: 先解决判定落子坐标的合法性问题,再使用“行行递进”的方式选定每行的落子坐标。
      问题1.判定落子坐标的合法性:使用四个数组x[],y[],k[],l[](初始=0)来记录各行各列各主斜线各副斜线是否已经有子(有子=1),此时给定第一个落子坐标(a,b)(任意坐标必然合法),
      落子完成,此时对四个数组进行更新x[a]=1,y[b]=1,k[x+y]=1,l[x-y]=1。再给定第2--n个落子(i,j),若x[i]=0,y[j]=0,k[i+j]=0,l[i-j]=0,说明该落子坐标满足条件“与其他落子不处于同 一行、同一列或同一斜线上”,此时即可落子完成,再次对四个数组更新······
      问题2.使用“行行递进”的方式选定每行的落子坐标:已知“每行必然有且只有一个落子”首先可以自定义第一行(即第一个落子的坐标),第一行有子后,进入第二行,进行遍历,直到找到合法坐标,再进入下一行······当进入至第n行(即最后一行),并成功落子,此时解法成立,将其print出来。
  • 关于啰嗦代码:

初试代码
#include<stdio.h>
int x[33],y[33],k[33],l[33],n;
int a[111][111];
int check(int xx,int yy)                       //判定落子坐标是否合法
{
    if(x[xx]||y[yy]||k[xx-yy]||l[xx+yy])
    {return 1;}
    else
    {return 0;}
}
void reset(int xx,int yy)                      //重置坐标
{
    a[xx][yy]=0;
    x[xx]=0;
    y[yy]=0;
    k[xx-yy]=0;
    l[xx+yy]=0;
}
void create(int xx,int yy)                     //创建坐标
{
    a[xx][yy]=1;
    x[xx]=1;
    y[yy]=1;
    k[xx-yy]=1;
    l[xx+yy]=1;
}

int search(int s)                              //递归遍历
{
    int f=0;
    for (int w=1;w<=n;w++)
    {
        if (check(s,w)==0)
        {
            create(s,w);
            if (s==n)
            {return 1;}
            if (search(s+1))
            {
                return 1;
            }
            else
            {
                reset(s,w);
                return 0;
            }
            f=1;
        }
    }
    if (f==1)
    {return 1;}
    else
    {return 0;}
}
int main()
{
    scanf("%d",&n);
    int f=0;
    if (n==1)
    {
        printf("Q");
        return 0;
    }
    for (int q=1;q<=n;q++)
    {
        //初始化状态
        f=0;
        for (int qq=0;qq<=20;qq++)
        {
            for (int ww=0;ww<=20;ww++)
            {a[qq][ww]=0;}
        }
        for (int qq=0;qq<=32;qq++)
        {
            x[qq]=0;y[qq]=0;k[qq]=0;l[qq]=0;
        }
        create(1,q);
        if (search(2))
        {
            f=1;
            for (int i=1;i<=n;i++)
            {
                for (int w=1;w<=n;w++)
                {
                    if (a[i][w])
                    {
                        printf("Q");
                    }
                    else
                    {
                        printf(".");
                    }
                }
                printf("\n");
            }
        }
        reset(1,q);
        if (f)
        {printf("\n");}
    }
}

初试代码AC失败,错误在于,递归的方式没有考虑到一行拥有多个分支的情况,只是一条路走到底,以至于最后print出的解法与答案相比还有缺失

最终版
#include<stdio.h>
int x[33],y[33],k[33],l[33],n;
int a[111][111];
int check(int xx,int yy)
{
    if(x[xx]||y[yy]||k[xx-yy]||l[xx+yy])
    {return 1;}
    else
    {return 0;}
}
void reset(int xx,int yy)
{
    a[xx][yy]=0;
    x[xx]=0;
    y[yy]=0;
    k[xx-yy]=0;
    l[xx+yy]=0;
}
void prl()
{
    for (int i=1;i<=n;i++)
            {
                for (int w=1;w<=n;w++)
                {
                    if (a[i][w])
                    {
                        printf("Q");
                    }
                    else
                    {
                        printf(".");
                    }
                }
                printf("\n");
            }
}
void create(int xx,int yy)
{
    a[xx][yy]=1;
    x[xx]=1;
    y[yy]=1;
    k[xx-yy]=1;
    l[xx+yy]=1;
}
int search(int s)
{
    int f=0,ff=0;
    for (int w=1;w<=n;w++)
    {
        if (check(s,w)==0)
        {
            create(s,w);
            if (s==n)
            {
                prl();
                f=1;
            }
            if (search(s+1))
            {
                f=1;
            }
            else
            {
                reset(s,w);
                f=0;
            }
        }
    }
    return f;
}
int main()
{
    scanf("%d",&n);
    int f=0;
    if (n==1)
    {
        printf("Q");
        return 0;
    }
    for (int q=1;q<=n;q++)
    {
        //初始化状态
        f=0;
        for (int qq=0;qq<=20;qq++)
        {
            for (int ww=0;ww<=20;ww++)
            {a[qq][ww]=0;}
        }
        for (int qq=0;qq<=32;qq++)
        {
            x[qq]=0;y[qq]=0;k[qq]=0;l[qq]=0;
        }
        create(1,q);
        if (search(2))
        {
            f=1;
        }
        reset(1,q);
        if (f)
        {printf("\n");}
    }
}

相比与初试代码,主要在递归函数里做了一些改动,使其可以遍历一整行的所有可能,给出的解法更完全

有待改善:相比于题库中给出的其他题解,这套代码显得十分臃肿啰嗦,应该系统性的学习一下相关的算法知识,以更简洁更规范的方式解答

posted @ 2021-10-12 21:13  酱鱼  阅读(36)  评论(0编辑  收藏  举报