您的位置:首页 > 其它

USACO 1.5.4 Checker Challenge 题解

2012-03-25 20:00 323 查看

【算法】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,证明所有的列都放置了棋子,则找到一个解。

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

View Code

/*
ID: wsc5001
LANG: C
TASK: checker
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int n;
int aone=0,amore=0;//aone:二进制最大值
int ansct=0;
int saveans[15]={0},si=0;
int finans[73715][15],fi=0;
void printans()
{
int i;
for (i=0;i<n;i++)
finans[fi][i]=saveans[i];
fi++;
}
void findfs(int lc,int rc,int row)//lc 左对角线 rc 右对角线 row 纵列    1=不可放 0=可放
{
int i,togt;
if (row!=aone)
{
togt=lc|rc|row;
for (i=0;i<n;i++)
{
if ((togt&1)==0)
{
{saveans[si]=n-i;si++;}
findfs((lc+(1<<i))<<1,(rc+(1<<i))>>1,row+(1<<i));
{saveans[si]=0;si--;}
}
togt=togt>>1;
}
}
else
{printans();ansct++;return;}
}
int main()
{
FILE *fin,*fout;
fin=fopen("checker.in","r");
fout=fopen("checker.out","w");
fscanf(fin,"%d",&n);
int i,j,k;
int av=0;
aone=(1<<n)-1;

findfs(0,0,0);
//printf("%d",si);
for (i=fi-1;i>=fi-3;i--)
{
for (j=0;j<n-1;j++)
fprintf(fout,"%d ",finans[i][j]);
fprintf(fout,"%d",finans[i][j]);
fprintf(fout,"\n");
}
//printf("\n");
fprintf(fout,"%d\n",ansct);

//system("pause");
fclose(fin);
fclose(fout);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: