您的位置:首页 > 其它

BZOJ 1087 互不侵犯King 状态压缩DP

2017-09-11 15:11 232 查看
题意:在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子,n<=9,k<=n*n;

n<=9,每行的状态可以用9位二进制数表示,令dp[i][j][k] 前i行放了j个第i行状态为k时的方案数.
则一行一行放 预处理(i,j)两个状态是否可以为相邻行后,合法转移状态即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e3+20;
bool s
,nei

;
ll f[10][100]
;
int n,k,num
;
void init()
{
for(int i=0;i<(1<<n);i++)
{
int t=i,pre=0,cnt=0;
if((i&(i<<1))==0)
{
for(int j=0;j<n;j++)
if((t>>j)&1)
cnt++;
s[i]=true,num[i]=cnt;
}
}
memset(nei,0,sizeof(nei));
for(int i=0;i<(1<<n);i++)
{
if(s[i])
{
for(int j=0;j<(1<<n);j++)
{
if(s[j])
{
if((i&j)==0 && (i&(j<<1))==0 && (j&(i<<1))==0)
nei[i][j]=true;
}
}
}

}
}
int main()
{
cin>>n>>k;
init();
memset(f,0,sizeof(f));
f[0][0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=k;j++)
{
for(int p=0;p<(1<<n);p++)
{
if(s[p])
for(int t=0;t<(1<<n);t++)
{
if(s[t]&&nei[p][t]&&j>=num[p]+num[t])
f[i][j][p]+=f[i-1][j-num[p]][t];
}
}
}
}
ll ans=0;
for(int i=0;i<(1<<n);i++)
if(f
[k][i]!=-1)
ans+=f
[k][i];
cout<<ans<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: