zoukankan      html  css  js  c++  java
  • 八皇后(DFS)

    原题:

    八皇后

    时间限制: 1 Sec  内存限制: 256 MB

    题目描述

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

     

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

    行号1 2 3 4 5 6

    列号2 4 6 1 3 5

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

     

    输入格式

    一行一个正整数 n,表示棋盘是 n×n 大小的。

     

    输入格式

    前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

     

    输入输出样例

    输入

    6
    输出

    2 4 6 1 3 5

    3 6 2 5 1 4

    4 1 5 2 6 3

    4


    题意:

           一道经典的DFS,题意不解释了题目说的很明白了。(逃


     

           这道题在《一本通》里有解析和代码,这里简单讲一讲思路。

           这是《一本通》中的源代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 bool d[10005],b[10005],c[10005];
     4 char a[14],e[14]={'A','A','B','C','D','E','F','G','H','I','J','K','L','M'};
     5 int sum,k;
     6 int print()
     7 {
     8     int i;
     9     sum++;
    10     if(sum<=3)
    11     {
    12         for(i=1;i<=k;i++)    printf("%d ",a[i]);
    13         printf("
    ");    
    14     }
    15 }
    16 int search(int i,int k)
    17 {
    18     int j;
    19     for(j=1;j<=k;j++)
    20         if(!b[j] && !c[i+j] && !d[i-j+k-1])
    21         {
    22             a[i]=j;
    23             b[j]=1;
    24             c[i+j]=1;
    25             d[i-j+k-1]=1;
    26             if(i==k)  print();
    27             else  search(i+1,k);
    28             b[j]=0;
    29             c[i+j]=0;
    30             d[i-j+k-1]=0;
    31         }
    32 }
    33 int main()
    34 {
    35     scanf("%d",&k);
    36     search(1,k);
    37     printf("%d",sum);
    38 return 0;
    39 }

           这道题首先很容易想到的是DFS暴力搜索,枚举所有点再考虑这个点是否可以安放棋子。有些第一次做这道题的萌新(比如之前的我)对于检验棋子是否可以安放无从下手,其实思路并不复杂。

           仔细观察这张图的行号和列号。

           你发现了什么?

           找规律是个好办法

           对角线的判断,我们可以对每一条假想的对角线编一个号,如按左下——右上方向编组,(1,1)属于一组,(1,2),(2,1)属于一组,(3,1),(2,2),(1,3)属于另一组......

           很容易发现我们新编的组中,同组的每一对数中的行号和列号相加的值总为一个定值,所以我们用一个数组f2来记录我们定义的新组。

           同样的按左上——右下编组,(1,6)属于一组,(1,5),(2,6)属于一组,(1,4),(2,5),(3,6)属于另一组......

           在这个新编的组中,每一对数的行号和列号的差总为一定值(超简单对不对),所以我们用数组f3来标记这个新数组。

           判断行、列是否重复很简单就不赘述了。

    带解析的代码如下(换了个码风(^o^)假装是另一篇代码):

     1 #include<iostream>
     2 #include<stdio.h>
     3 using namespace std;
     4 int n,ans,pos[15],f1[25],f2[25],f3[25],f4[25];
     5 void print()
     6 {
     7     ans++;
     8     if(ans>3)  return;//只输出前三个答案 
     9     printf("%d",pos[1]);
    10     for(int i=2;i<=n;i++)  printf(" %d",pos[i]);//打印 
    11     printf("
    ");
    12 return;
    13 }
    14 void dfs(int x)
    15 {
    16     //x代表目前正在将第x颗棋子放置在第x行, 
    17     if(x==n+1)  { print(); return; }
    18     for(int i=1;i<=n;i++)//尝试第x行第i列 
    19         if(!f1[i] && !f2[i+x] && !f3[i-x+n])
    20         {
    21             f1[i]=f2[i+x]=f3[i-x+n]=1,pos[x]=i;
    22             //pos记录答案,f3数组中为防止下标为负数需要+n 
    23             dfs(x+1);
    24             //回溯 
    25             f1[i]=f2[i+x]=f3[i-x+n]=0;
    26         }
    27 }
    28 int main()
    29 {
    30     scanf("%d",&n);
    31     dfs(1);//从第1枚棋子开始放置 
    32     printf("%d
    ",ans);
    33 return 0;
    34 }
  • 相关阅读:
    201521123105 第8周Java学习总结
    201521123105 第七周Java学习总结
    201521123105 第六周Java学习总结
    201521123105 第四周Java学习总结
    201521123105 第三周Java学习总结
    201521123105《jave程序》第二周学习总结
    201521123105 《Java程序设计》第1周学习总结
    网络15软工个人作业5——软件工程总结
    个人作业4——alpha阶段个人总结
    软件工程网络15个人作业3——案例分析
  • 原文地址:https://www.cnblogs.com/leaf-2234/p/13862651.html
Copyright © 2011-2022 走看看