题意:
给你一个(n*n)的格子,如果第(i)个格子放入了棋子,则八联通方向都不能放置棋子,问放置(k)个棋子的方案数。
分析:
很明显可以进行(dp),又因为(n)非常的小,因此我们可以采用状态压缩的方法。设(dp[i][state][k])为当前第(i)行的状态为(state)时,放置了(k)个棋子的方案数。
当前第i行的状态,显然可以由第(i-1)行的状态转移而来,而因为要满足八联通不能有棋子,因此在我们的状压(state[I]),和(state[j])中,只要满足(state[i]&(state[i]<<1))、(state[j]&(state[j]<<1))、(state[i]&(state[j]<<1))、(state[i]&(state[j]>>1))、(state[I]&state[j])均大于(0)即可。最后有状态转移方程:(dp[i][state[i]][bit(state[i])+k]+=dp[I-1][bit(state[j])][k])
总的时间复杂度为:(mathcal{O}(2^{2*n}*k))
代码:
#include <bits/stdc++.h>
#define maxn 10
using namespace std;
long long dp[maxn][1<<maxn][maxn*maxn];
int getbit(int x){
int res=0;
while(x){
if(x&1) res++;
x>>=1;
}
return res;
}
int main()
{
int n,k;
memset(dp,0,sizeof(dp));
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
int all=1<<n;
for(int j=0;j<all;j++){
if(j&(j<<1)) continue;
if(i==1){
if(getbit(j)<=k) dp[i][j][getbit(j)]++;
continue;
}
for(int kk=0;kk<all;kk++){
if(kk&(kk<<1)) continue;
if((j&kk)||(j&(kk<<1))||(j&(kk>>1))) continue;
for(int ll=0;ll<=k;ll++){
dp[i][j][getbit(j)+ll]+=dp[i-1][kk][ll];
}
}
}
}
long long res=0;
int all=1<<n;
for(int i=0;i<all;i++){
res+=dp[n][i][k];
}
printf("%lld
",res);
return 0;
}