比起普通的搜索剪枝来,由于在每一层的搜索里多加了两个限定条件ld/rd——斜对角线,加之使用取最低位的操作,大大减少了每一层的遍历时间。
这是USACO1.5的最后一题,要求列出字典序遍历结果的前三位。在N=13的情形下,运行时间0.163S。
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;
int Ans;
int N;
int Mask;
int Case;
int Path[20];
ifstream fin ( "checker.in" );
ofstream fout ( "checker.out" );
int log2 ( int n )
{
if ( n == 1 )
return 0;
return log2 ( n >> 1 ) + 1;
}
void print ()
{
int i;
for ( i = 0; i < N; i ++ )
{
if ( i )
fout << " ";
fout << Path[i];
}
fout << endl;
}
void dfs ( int x, int ld, int rd )
{
if ( x == Mask )
{
Ans ++;
return;
}
int avail = ~ ( x | ld | rd ) & Mask;
int i;
while ( avail )
{
i = avail & ( -avail ); // 取最低位
avail -= i;
dfs ( x + i, ( ld + i ) << 1, ( rd + i ) >> 1 );
}
}
void dfs3 ( int depth, int x, int ld, int rd )
{
if ( Case >= 3 )
return;
if ( x == Mask )
{
Case ++;
print ();
return;
}
int avail = ~ ( x | ld | rd ) & Mask;
int i;
while ( avail )
{
i = avail & ( -avail );
Path[depth] = log2 ( i ) + 1;
avail -= i;
dfs3 ( depth + 1, x + i, ( ld + i ) << 1, ( rd + i ) >> 1 );
}
}
int main ()
{
fin >> N;
Mask = ( 1 << N ) - 1;
Ans = 0, Case = 0;
dfs3 ( 0, 0, 0, 0 );
dfs ( 0, 0, 0 );
fout << Ans << endl;
return 0;
}