P1896 互不侵犯

题面:https://www.luogu.org/problemnew/show/P1896

经典的状压dp,dp方程:f[i][j][k]+=f[i-1][j-num[k]][l];
还有位运算的判断也很重要

Code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<bitset>
#include<ctime>
#include<stack>
using namespace std;
const int N=10005,M=15;
long long n,k1,num[N],s[N],f[M][M][N],tot,ans;
long long lowbit(long long x){
    return x&(-x);
}
int main(){
    scanf("%lld%lld",&n,&k1);
    for(int i=0;i<(1<<n);i++){
        if(!(i&(i<<1))){
            int sum=0,t=i;
            ++tot;
            while(t){
                t-=lowbit(t);
                ++sum;
            }
            num[tot]=sum;
            s[tot]=i;
        }
    }
    for(int i=1;i<=tot;i++){
        if(num[i]>k1)
            continue;
        f[1][num[i]][i]=1;
    }
    for(int i=2;i<=n;i++){
        for(int j=0;j<=k1;j++){
            for(int k=1;k<=tot;k++){
                if(num[k]>j)
                    continue;
                for(int l=1;l<=tot;l++){
                    if(num[l]>j-num[k])
                        continue;
                    if(s[k]&s[l])
                        continue;
                    if(s[k]&(s[l]<<1))
                        continue;
                    if(s[l]&(s[k]<<1))
                        continue;
                    f[i][j][k]+=f[i-1][j-num[k]][l];
                }
            }
        }
    }
    for(int j=1;j<=tot;j++){
        ans+=f[n][k1][j];
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2019-07-16 13:46  prestige  阅读(129)  评论(0编辑  收藏  举报