zoukankan      html  css  js  c++  java
  • P1219 八皇后 含优化 1/5

    题目描述

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

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

    行号 1 2 3 4 5 6

    列号 2 4 6 1 3 5

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

    //以下的话来自usaco官方,不代表洛谷观点

    特别注意: 对于更大的N(棋盘大小N x N)你的程序应当改进得更有效。不要事先计算出所有解然后只输出(或是找到一个关于它的公式),这是作弊。如果你坚持作弊,那么你登陆USACO Training的帐号删除并且不能参加USACO的任何竞赛。我警告过你了!

    输入输出格式

    输入格式:

    一个数字N (6 <= N <= 13) 表示棋盘是N x N大小的。

    输出格式:

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

    输入输出样例

    输入样例#1: 复制
    6
    
    输出样例#1: 复制
    2 4 6 1 3 5
    3 6 2 5 1 4
    4 1 5 2 6 3
    4



    紫书上的八皇后
    普通方法 555ms
    #include<iostream>//个人不建议采用头文件,可能和定义的变量或名字起冲突,从而引起编译错误;
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    int a[100],b[100],c[100],d[100];
    //a数组表示的是行;
    //b数组表示的是列;
    //c表示的是左下到右上的对角线;
    //d表示的是左上到右下的对角线;
    int total;//总数:记录解的总数
    int n;//输入的数,即N*N的格子,全局变量,搜索中要用
    int print()
    {
        if(total<=2)//保证只输出前三个解,如果解超出三个就不再输出,但后面的total还需要继续叠加
        {
            for(int k=1;k<=n;k++)
            cout<<a[k]<<" ";//for语句输出
            cout<<endl;
        }
        total++;//total既是总数,也是前三个排列的判断
    }
    void queen(int i)//搜索与回溯主体
    {
        if(i>n)
        {
            print();//输出函数,自己写的
            return;
        }
        else
        {
            for(int j=1;j<=n;j++)//尝试可能的位置
            {
                if((!b[j])&&(!c[i+j])&&(!d[i-j+n]))//如果没有皇后占领,执行以下程序
                {
                    a[i]=j;//标记i排是第j个
                    b[j]=1;//宣布占领纵列
                    c[i+j]=1;
                    d[i-j+n]=1;
                    //宣布占领两条对角线
                    queen(i+1);//进一步搜索,下一个皇后
                    b[j]=0;
                    c[i+j]=0;
                    d[i-j+n]=0;
                    //(回到上一步)清除标记
                }
            }
        }
    }
    int main()
    {    
        cin>>n;//输入N*N网格,n已在全局中定义
        queen(1);//第一个皇后
        cout<<total;//输出可能的总数
        return 0;
    }
    View Code
    加速  99ms
    #include<cstdio>
    int upperlim,n,ans,tot,plan[15];
    void dfs(int i,int c,int ld,int rd)//变量含义:第i行(只是用来记录方案,如果不输出方案,可以去掉),c是行影响,ld、rd分别是左右对角线
    {
      if(c==upperlim)//很好理解,如果是一个可行解的话自然所有列上都有棋子,如果不是可行解,看下面
      {
        if(++ans<=3)
        {
          for(int i=1;i<n;i++)
            printf("%d ",plan[i]);
          printf("%d
    ",plan[n]);
        }
        return;
      }
      int mask=upperlim&~(ld|rd|c);//mask指的是留下来能用的位置,受到行、左右对角线的影响。用upperlim & 则是要舍掉高位上多出来的1
      while(mask)//尽管是穷举位,但是不用判断,因为如果不可行的话mask上没有能放的位置,根本到达不了最终状态就退出,位运算解法天然剪枝的高效、简洁是别的解法永远也追不上的
      {
        int p=mask&(-mask);//技巧,表示mask末尾的第一个1,也就是穷举能放的位置
        mask-=p;//
        plan[i]=__builtin_ffs(p);//__builtin_ffs(p)指的是p的末尾第一个1的位置,竞赛能不能用我不知道,但是据说有人WinterCamp用了AC
        dfs(i+1,c|p,(ld|p)<<1,(rd|p)>>1);//状态转移,c|p是行上影响,ld:对角线上首先增加了p的影响很好理解,左移则是对角线向下一行的自然延伸,rd同理
      }
    }
    //尽管注释很详细,但是还是自己敲2,3遍才能理解
    int main()
    {
      scanf("%d",&n);
      upperlim=(1<<n)-1;//目标状态
      ans=0;
      dfs(1,0,0,0);
      printf("%d
    ",ans);
      return 0;
    }
    View Code


  • 相关阅读:
    npm 常用指令
    跨域详解
    模板
    Set-Cookie
    哈佛大学公开课 幸福课 积极心理学
    Token Authentication vs. Cookies
    Using Cookieless Forms Authentication Tickets
    What Is Token-Based Authentication and Who Uses It?
    Types of authentication wiz. oauth, digest, basic, token-based
    Session Authentication vs Token Authentication
  • 原文地址:https://www.cnblogs.com/bxd123/p/10531870.html
Copyright © 2011-2022 走看看