zoukankan      html  css  js  c++  java
  • USACO 1.5.4 Checker Challenge 题解

    【算法】DFS  【难度】★★★★☆


     思路:经典的N皇后问题,但是对于6 <= N <= 13的范围朴素搜索1s内无法出结果。所以要考虑加速。考虑到剪枝的优化空间有限,所以本题才用位运算+DFS。

    事实上,这个思路来自于Matrix67的文章,按照我自己的理解描述一下:

    同样是一个DFS的递归,带有三个参数row,lc,rc分别标记这一横行上受到纵列(|)、右倾对角线(\)和左倾对角线(/)上已经放过的棋子的影响有冲突的位置标记方法是按位表示:用0表示无冲突,1表示有冲突

    例如,如果一个6皇后的某次的lc二进制下为100101,这表示在第1、4、6个位置受到右倾对角线上已放过棋子的限制,在这一行上不能放。

    由于每一横行上只能放一个,所以每次过程中将row,lc,rc中的所有禁位算出来并找出可以放棋子的位置,并递归。递归前把选中放棋子的位置对应的row,lc,rc中的相应位变为1。

    当递归到某次时发现row的所有位都为1,证明所有的列都放置了棋子,则找到一个解。

    利用这种方法速度非常的快:

    最大的数据(n==13)时也只要0.227s,这是直接DFS比不了的。

    PS.  Matrix67关于位运算有一系列文章都写得很好,相当经典

    http://www.matrix67.com/blog/archives/122

    个人觉得他的博客很不错,很多讲解都清晰透彻。

    View Code
     1 /*
    2 ID: wsc5001
    3 LANG: C
    4 TASK: checker
    5 */
    6 #include <stdio.h>
    7 #include <stdlib.h>
    8 #include <math.h>
    9 int n;
    10 int aone=0,amore=0;//aone:二进制最大值
    11 int ansct=0;
    12 int saveans[15]={0},si=0;
    13 int finans[73715][15],fi=0;
    14 void printans()
    15 {
    16 int i;
    17 for (i=0;i<n;i++)
    18 finans[fi][i]=saveans[i];
    19 fi++;
    20 }
    21 void findfs(int lc,int rc,int row)//lc 左对角线 rc 右对角线 row 纵列 1=不可放 0=可放
    22 {
    23 int i,togt;
    24 if (row!=aone)
    25 {
    26 togt=lc|rc|row;
    27 for (i=0;i<n;i++)
    28 {
    29 if ((togt&1)==0)
    30 {
    31 {saveans[si]=n-i;si++;}
    32 findfs((lc+(1<<i))<<1,(rc+(1<<i))>>1,row+(1<<i));
    33 {saveans[si]=0;si--;}
    34 }
    35 togt=togt>>1;
    36 }
    37 }
    38 else
    39 {printans();ansct++;return;}
    40 }
    41 int main()
    42 {
    43 FILE *fin,*fout;
    44 fin=fopen("checker.in","r");
    45 fout=fopen("checker.out","w");
    46 fscanf(fin,"%d",&n);
    47 int i,j,k;
    48 int av=0;
    49 aone=(1<<n)-1;
    50
    51 findfs(0,0,0);
    52 //printf("%d",si);
    53 for (i=fi-1;i>=fi-3;i--)
    54 {
    55 for (j=0;j<n-1;j++)
    56 fprintf(fout,"%d ",finans[i][j]);
    57 fprintf(fout,"%d",finans[i][j]);
    58 fprintf(fout,"\n");
    59 }
    60 //printf("\n");
    61 fprintf(fout,"%d\n",ansct);
    62
    63 //system("pause");
    64 fclose(fin);
    65 fclose(fout);
    66 }



  • 相关阅读:
    阅读《最后期限》有感(1)
    软件工程课程改进建议
    团队开发第二次冲刺第七天
    返回一个二维整数数组中最大联通子数组的和
    大道至简阅读笔记三
    大道至简阅读笔记二
    大道至简阅读笔记一
    团队冲刺阶段二第十次站立会议
    对软工课程的意见建议
    团队冲刺阶段二第九次站立会议
  • 原文地址:https://www.cnblogs.com/loveidea/p/2416960.html
Copyright © 2011-2022 走看看