八皇后(弱版)

今天教你如何O2水过八皇后...

题目:

检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

上面的布局可以用序列2 4 6 1 3 5来描述,第i个数字表示在第i行的相应位置有一个棋子,如下:

行号 1 2 3 4 5 6

列号 2 4 6 1 3 5

这只是跳棋放置的一个解。请编一个程序找出所有跳棋放置的解。并把它们以上面的序列方法输出。解按字典顺序排列。请输出前3个解。最后一行是解的总个数。

这道题为明显的深搜题,具体算法...暴力枚举每一个合法的位置组合,(横)坐标从小到大遍历可保证字典序问题

结合具体代码分析思路:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
int used[15][15];
int q[15];
int t;
int tim;
inline void search(int pos){for(int i=1;i<=n;i++){
        if(!used[i][pos]){
            t++;
            q[t]=i;
            if(t==n){
                tim++;
                if(tim<=3){
                    for(int j=1;j<=n;j++)
                        printf("%d ",q[j]);
                    puts("");
                }
            }
            else{
                for(int j=1;j<=n;j++){
                    used[j][pos]++;
                    used[i][j]++;
                }
                for(int j=max(pos+i-n,1);j<=min(pos+i-1,n);j++)
                    used[j][pos+i-j]++;
                for(int j=max(pos-i+1,1),t=max(i-pos+1,1);j<=min(pos-i+n,n);j++,t++)
                    used[t][j]++;
                search(pos+1);
                for(int j=1;j<=n;j++){
                    used[j][pos]--;
                    used[i][j]--;
                }
                for(int j=max(pos+i-n,1);j<=min(pos+i-1,n);j++)
                    used[j][pos+i-j]--;
                for(int j=max(pos-i+1,1),t=max(i-pos+1,1);j<=min(pos-i+n,n);j++,t++)
                    used[t][j]--;
            }
            t--;
        }
    }
}
int main(){
    scanf("%d",&n);
    search(1);
    printf("%d",tim);
    return 0;
}

利用used数组保存地图状态,如果不为0即为使用,注意该数组不能用bool,因为多个皇后的势力范围一定会出现覆盖,如果用bool则会在回溯操作时将不该删除的其他皇后势力范围删掉,使用int进行逐层覆盖即可,

关于每个皇后势力范围划分问题,也就是如何根据皇后坐标找对角线的问题,建议画一个图自己去推,很锻炼模拟能力,

至于本代码中pos与i哪个是横坐标哪个是纵坐标...我好像也不知道...在推导皇后势力范围公式时搞反了,导致两变量所处位置与思路中完全不符,然而这并没有关系,因为本题中棋盘为正方形,可以将横纵坐标反过来,也许思路想对横坐标进行搜索枚举,最终也仅是将纵坐标当做结果输出即可

最后,search函数搜索主程序后面的t--必不可少,它是回溯操作的关键,即删去原添加坐标的序号,表示未进行该操作。

再说一下关于时间限制的问题(开O2):

不用inline的时间:

444ms

用了inline的时间:

443ms

(显然inline要快嘛~)

不开O2就会突破天际直奔2000ms

正经考试中这种算法不开O2在该数据范围内仅会WA一个点,还是相当划算的,不过13分没了

6.13update

其实这题不用非常麻烦的赋值语句,把used一个一个赋值,只需开个以为数组并找到合适的标识(比如与y轴的焦点纵坐标)来表示行,列,对角线,就能非常容易地标识使用路径,比无脑赋值效率高太多

至于为什么不写代码...去看6.13的博客去

原文地址:https://www.cnblogs.com/648-233/p/10964300.html