您的位置:首页 > 其它

【BZOJ】1087: [SCOI2005]互不侵犯King

2016-09-12 20:05 274 查看

【算法】状态压缩型DP

【题解】http://www.cnblogs.com/xtx1999/p/4620227.html (orz)

https://www.cnblogs.com/zbtrs/p/6189240.html

dp[i][j][k]为前i行已经放了j个国王并且第i行的状态为k(二进制)的方案数。

状态左移右移预处理两行合法。

dp[i][j][k] = Σdp[i-1][j - num[k]][p]

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=10,e2=530;
long long f[maxn][e2][maxn*maxn];
int n,mk,num[e2],king[e2],ok[e2][e2];
bool selfcheck(int a)
{
return !(a&(a>>1));
}
int calc(int a)
{
int cyc=0;
while(a)
{
if(a&1)cyc++;
a=a>>1;
}
return cyc;
}
bool check(int a,int b)
{
if((a&b)||(a&(b<<1))||(a&(b>>1)))return 0;
return 1;

}
int main()
{
scanf("%d%d",&n,&mk);
int all=(1<<n)-1,tot=0;
for(int i=0;i<=all;i++)
{
if(selfcheck(i))
{
num[++tot]=i;
king[tot]=calc(i);
//printf("%d\n",i);
}
}
for(int i=1;i<=tot;i++)
for(int j=1;j<=tot;j++)
if(!ok[i][j])if(check(num[i],num[j]))
ok[i][j]=ok[j][i]=1;//,printf("%d %d\n",i,j);
f[0][1][0]=1;
for(int i=0;i<=n-1;i++)
for(int j=1;j<=tot;j++)
for(int k=0;k<=mk;k++)
if(f[i][j][k])
for(int p=1;p<=tot;p++)
if(ok[j]

&&k+king[p]<=mk) f[i+1][p][k+king[p]]+=f[i][j][k]; long long ans=0; for(int i=1;i<=tot;i++) ans+=f [i][mk]; printf("%lld",ans); return 0; }

View Code [p] 

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