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
思路: 状压dp, dp(i,j,s)代表到了第i行,已经有k个king,第i行状态是s。转移就可以了
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
ll dp[10][1005][1005],num[1005],sta[1005];
int flag[1005];
int main()
{
int n,k;scanf("%d%d",&n,&k);
int cnt = 0;
for(int i = 0;i < (1 << n);i++)
{
if(!(i & (i << 1)))
{
int tmp = i;
while(tmp)
{
num[i] += (tmp & 1);
tmp >>= 1;
}
sta[++cnt] = i;
dp[1][num[i]][i] = 1;
}
}
for(int i = 2;i <= n;i++)
{
for(int j = 0;j <= k;j++)
{
for(int now = 1;now <= cnt;now++)
{
if(num[sta[now]] > j)
continue;
for(int last = 1;last <= cnt;last++)
{
if((sta[now] & sta[last]) || (sta[now] & (sta[last] >> 1)) || ((sta[now]) & sta[last] << 1))
continue;
dp[i][j][sta[now]] += dp[i - 1][j - num[sta[now]]][sta[last]];
}
}
}
}
ll ans = 0;
for(int i = 1;i <= cnt;i++)
{
ans += dp[n][k][sta[i]];
}
printf("%lld\n",ans);
return 0;
}
AC NEW
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
ll dp[11][1 << 10][1 << 10];
ll sta[1 << 10],num[1 << 10];
int main()
{
ll n,m;scanf("%lld%lld",&n,&m);
ll cnt = 0;
for(ll i = 0;i < (1 << n);i++)
{
if(!(i & (i << 1)))
{
ll tmp = i;
while(tmp)
{
num[i] ++;
tmp = tmp & (tmp - 1);
}
sta[++cnt] = i;
dp[1][num[i]][i] = 1;
}
}
for(ll i = 2;i <= n;i++)
{
for(ll j = 0;j <= m;j++)
{
for(ll now = 1;now <= cnt;now++)
{
if(num[sta[now]] <= j)
{
for(ll last = 1;last <= cnt;last++)
{
if((sta[now] & sta[last]) == 0 && ((sta[now] << 1 & sta[last]) == 0) && ((sta[now] >> 1 & sta[last]) == 0))
{
dp[i][j][sta[now]] += dp[i - 1][j - num[sta[now]]][sta[last]];
}
}
}
}
}
}
ll ans = 0;
for(ll i = 1;i <= cnt;i++)
{
ans += dp[n][m][sta[i]];
}
printf("%lld\n",ans);
return 0;
}