您的位置:首页 > 其它

BZOJ1087 [SCOI2005]互不侵犯King 状态压缩DP

2017-09-20 10:37 465 查看

大家都很强,可与之共勉 。

DP

注意枚举顺序与如何设计状态

转移实际上是一种背包

Description

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

左下右上右下八个方向上附近的各一个格子,共8个格子。

Input

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

Output

  方案数。

Sample Input

3 2

Sample Output

16

# include <bits/stdc++.h>

long long dp [11] [105] [( 1 << 10 ) | 1], ans ;

int main ( )  {
int n, m ;
scanf ( "%d%d", & n, & m ) ;
int lim = ( 1 << n ) ;
dp [0] [0] [0] = 1 ;
for ( int i = 1 ; i <= n ; ++ i )  {
for ( int j = 0 ; j < lim ; ++ j ) // last
if ( ! ( j &  ( j << 1 ) ) )  {
for ( int k = 0 ; k < lim ; ++ k )  // cur
if ( ! ( k & ( k << 1 ) ) && ! ( j & k ) && ! ( ( j << 1 ) & k ) && ! ( ( j >> 1 ) & k ) )  {
int cnt = __builtin_popcount ( k ) ;
for ( int l = cnt ; l <= m ; ++ l )  {
dp [i] [l] [k] += dp [i - 1] [l - cnt] [j] ;
}
}
}
}
for ( int i = 0 ; i < lim ; ++ i )  ans += dp
[m] [i] ;
printf ( "%lld\n", ans ) ;
}


换一个方式枚举,速度快了不少。

# include <bits/stdc++.h>

long long dp [11] [105] [( 1 << 10 ) | 1], ans ;

int main ( )  {
int n, m ;
scanf ( "%d%d", & n, & m ) ;
int lim = ( 1 << n ) ;
dp [0] [0] [0] = 1 ;
for ( int i = 1 ; i <= n ; ++ i )  {
for ( int j = 0 ; j < lim ; ++ j ) // cur
if ( ! ( j &  ( j << 1 ) ) )  {
for ( int k = 0 ; k < lim ; ++ k )  // last
if ( ! ( k & ( k << 1 ) ) && ! ( j & k ) && ! ( ( j << 1 ) & k ) && ! ( ( j >> 1 ) & k ) )  {
int cnt = __builtin_popcount ( j ) ;
for ( int l = cnt ; l <= m ; ++ l )  {
dp [i] [l] [j] += dp [i - 1] [l - cnt] [k] ;
}
}
}
}
for ( int i = 0 ; i < lim ; ++ i )   ans += dp
[m] [i] ;
printf ( "%lld\n", ans ) ;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: