BZOJ 1087: [SCOI2005]互不侵犯King( 状压dp )

简单的状压dp...

dp( x , h , s ) 表示当前第 x 行 , 用了 h 个 king , 当前行的状态为 s .

考虑转移 : dp( x , h , s ) = ∑ dp( x - 1 , h - cnt_1( s ) , s' ) ( s and s' 两行不冲突 , cnt_1( s ) 表示 s 状态用了多少个 king )

我有各种预处理所以 code 的方程和这有点不一样

----------------------------------------------------------------------------------

#include<cstdio>

#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#include<iostream>
 
#define clr( x , c ) memset( x , c , sizeof( x ) )
#define rep( i , n ) for( int i = 0 ; i < n ; ++i )
#define b( i ) ( 1 << ( i ) )
 
using namespace std;
 
typedef long long ll;
const int maxn = 10;
const int maxstate = 100;
 
vector< int > state;
vector< int > cnt;
vector< int > ok[ maxstate ];
int n , k;
ll d[ maxn ][ maxn * maxn ][ maxstate ];
 
void init() {
state.clear() , cnt.clear();
clr( d , -1 );
clr( d[ 0 ] , 0 );
cin >> n >> k;
rep( s , b( n ) ) if( ! ( s & ( s << 1 ) ) ) {
state.push_back( s );
int t = 0;
   for( int h = s ; h ; h >>= 1 ) t += h & 1;
   cnt.push_back( t );
   d[ 0 ][ t ][ state.size() - 1 ] = 1;
}
rep( i , state.size() ) 
   ok[ i ].clear();
rep( i , state.size() )
for( int j = i ; j < state.size() ; j++ )
   if( ! ( state[ j ] & state[ i ] ) && ! ( ( state[ j ] << 1 ) & state[ i ] ) && ! ( ( state[ i ] << 1 ) & state[ j ] ) ) {
       ok[ i ].push_back( j );
       if( i != j ) ok[ j ].push_back( i );
   }
}
 
ll dp( int x , int h , int t ) {
if( h < 0 ) return 0;
ll &ans = d[ x ][ h ][ t ];
if( ans != -1 ) return ans;
ans = 0;
if( h < cnt[ t ] ) return ans;
for( vector< int > :: iterator it = ok[ t ].begin() ; it != ok[ t ].end() ; it++ )
   ans += dp( x - 1 , h - cnt[ t ] , *it );
return ans;
}
 
void work() {
ll ans = 0;
    rep( i , state.size() ) 
   ans += dp( n - 1 , k , i );
cout << ans << "\n";
}
 
int main() {
// freopen( "test.in" , "r" , stdin );
// freopen( "test.out", "w", stdout );
init();
work();
    return 0; 

---------------------------------------------------------------------------------- 

 

1087: [SCOI2005]互不侵犯King

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 1974   Solved: 1171
[ Submit][ Status][ Discuss]

Description

在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。

Input

只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

Output

方案数。

Sample Input

3 2

Sample Output

16

HINT

Source

 

你可能感兴趣的:(ZOJ)