bzoj 1087: [SCOI2005]互不侵犯King【状压dp】

显然是状压,设f[i][j][k]为1到i行选j个king,并且第i行状态为k的方案数,判断是否可行然后枚举转移即可
先把可行状态预处理出来会变快

#include<iostream>
#include<cstdio>
using namespace std;
const int N=2005;
long long n,kk,a[N],sum[N],tot,t,m,f[10][30][1005],ans;
bool v[N][N];
int main()
{
    scanf("%lld%lld",&n,&kk);
    if(kk>(n+1)/2*(n+1)/2)
    {
        printf("0");
        return 0;
    }
    m=(1<<n)-1;
    for(int i=0;i<=m;i++)
		if(!(i&(i<<1)))
		{
			t=0;
			for(int j=i;j;j>>=1)
				t+=(j&1);
			a[++tot]=i;
			sum[tot]=t;
		}
    for(int i=1;i<=tot;i++)
		for(int j=1;j<=tot;j++)
			if(!(a[i]&a[j])&&!(a[i]&(a[j]<<1))&!((a[i]<<1)&a[j]))
				v[i][j]=1;
    for(int i=1;i<=tot;i++)
		f[1][sum[i]][a[i]]=1ll;
    for(int i=2;i<=n;i++)
		for(int j=1;j<=tot;j++)
			for(int k=1;k<=tot;k++)
				if(v[j][k])
					for(int l=kk;l>=sum[j];l--)
						f[i][l][a[j]]+=f[i-1][l-sum[j]][a[k]];
    for(int i=1;i<=tot;i++)
		ans+=f[n][kk][a[i]];
    printf("%lld",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/lokiii/p/9387704.html