大家都很强,可与之共勉 。
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 [n] [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 [n] [m] [i] ;
printf ( "%lld\n", ans ) ;
}