数据结构学习之栈求解n皇后问题
0x1 目的
深入掌握栈应用的算法和设计
0x2 内容
编写一个程序exp3-8.cpp求解n皇后问题。
0x3 问题描述
即在n×n的方格棋盘上,放置n个皇后,要求每个皇后不同行、不同列、不同左右对角线。
要求:(1)皇后的个数n由用户输入,其值不能超过20,输出所有的解。(2)采用类似于栈求解迷宫问题的方法。
0x4 代码
- #include <iostream>
- #include <cstdio>
- #include <cstdlib>
- #include <string.h>
- #define MaxSize 100000+7
- #define maxsize 20+7
- using namespace std;
-
- int path[maxsize][maxsize];
- int n;
-
- int y_pos[maxsize];
- int count=0;
- bool judge(int num)
- {
- for(int i=0;i<num;i++)
- {
- if(y_pos[i]==y_pos[num] || abs(y_pos[num]-y_pos[i])==num-i)
- return false;
- }
- return true;
- }
- typedef struct
- {
- int x;
- int y;
- int di;
- }Box;
-
- typedef struct
- {
- Box data[MaxSize];
- int top;
- }StType;
-
- void InitStack(StType *&s)
- {
- s=(StType *)malloc(sizeof(StType));
- s->top=-1;
- }
-
- void DestroyStack(StType *&s)
- {
- free(s);
- }
-
- bool GetTop(StType *&s,Box &e)
- {
- if(s->top==-1)
- return false;
- e=s->data[s->top];
- return true;
- }
-
- bool push(StType *&s,Box e)
- {
- if(s->top==MaxSize-1)
- return false;
- s->top++;
- s->data[s->top]=e;
- return true;
- }
-
- bool pop(StType *&s,Box &e)
- {
- if(s->top==-1)
- return false;
- e=s->data[s->top];
- s->top--;
- return true;
- }
-
- int GetLength(StType *s)
- {
- return(s->top+1);
- }
-
- bool EmptyStack(StType *s)
- {
- return(s->top==-1);
- }
-
-
-
- void SetPath(int ex,int ey,int k)
- {
- int xi=ex;
- int yi=ey;
- for(int i=0;i<n;i++)
- {
- path[xi][i]+=k;
- path[i][yi]+=k;
- }
- int x1,x2,y1,y2;
- x1=x2=xi;
- y1=y2=yi;
- while(x1>0&&y1>0)
- path[--x1][--y1]+=k;
- while(x2<n&&y2<n)
- path[x2++][y2++]+=k;
- path[xi][yi]-=k*2;
- }
-
- void printSolution()
- {
- for(int i=0;i<n;i++)
- {
- for(int j=0;j<n;j++)
- {
- if(y_pos[i]==j)
- printf("q");
- else
- printf("*");
-
- }
- printf("\n");
- }
- printf("\n");
- }
-
- void Disp(StType *s)
- {
- for(int i=0;i<s->top;i++)
- printf("\t(%d,%d)",s->data[i].x,s->data[i].y);
- }
-
- void SolveQ(int n)
- {
- int x1,y1,di;
- StType *st;
- InitStack(st);
- Box e;
- e.x=0;
- e.y=-1;
- push(st,e);
- while(!EmptyStack(st))
- {
- GetTop(st,e);
- x1=e.x;
- y1=e.y;
- bool find=false;
- if(x1==n)
- {
- printSolution();
- Disp(st);
- printf("\n");
- count++;
- }
- while(y1<n-1 && !find)
- {
- y1++;
- y_pos[x1]=y1;
- st->data[st->top].y=y1;
- if(judge(x1))
- {
- find=true;
- e.x=x1+1;
- e.y=-1;
- push(st,e);
- }
- }
- if(!find)
- {
- pop(st,e);
- }
- //pop(st,e);
- }
- }
-
-
- int main()
- {
- printf("please input n:\n");
- scanf("%d",&n);
- memset(path,0,sizeof(path));
- memset(y_pos,0,sizeof(y_pos));
- SolveQ(n);
- printf("\n count:%d \n",count);
- return 0;
- }
-
0x5 结果
0x6 总结
当时我在写的时候很纠结从0开始的问题,思想肯定是这样子的,先遍历每一行的每一列,然后在回溯。那么就需要做好回溯的标志e.x
记录当前在第几行,方便下次回溯到e.x-1
,这里唯一需要注意的是判断打印条件,if(x1==n)
,一开始我以为既然已经让第七行进栈了,那么说明满足,但是后面我理解错了,程序的逻辑是下一行进栈开始的时候y1=-1的,也就是我们要去到第8行才能知道第7行的结果是可以的。