一天一DP计划状压DP

Posted sjsjsj-minus-si

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一天一DP计划状压DP相关的知识,希望对你有一定的参考价值。

##P1896 互不侵犯【状压dp】

  • 用01串表示每一行的可行解
  • 列与列之间的限制条件在转移的时候continue
  • x&=(-x)可以找到x的二进制位上有多少个1
  • 关于位运算的优先级!不确定就无脑加括号哦哦
reference:
    https://www.luogu.org/blog/virus2017/1896dnqec
Date:
    2019.10.04
*/
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define dwn(i,a,b) for(int i=a;i>=b;--i) 
template <typename T> inline void rd(T &x){x=0;char c=getchar();int f=0;while(!isdigit(c)){f|=c=='-';c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x=f?-x:x;} 
#define mem(a,b) memset(a,b,sizeof(a))

int f[9+5][512+5][81+5];
//f[i][j][k]表示第i行的状态选的是第j个状态,有k个国王的方案数
//上个状态:f[i-1][jj][k-cnt[j]]; 
int n,K,tot;
int st[512+5],cnt[512+5];
//st表示当前可行的状态(01串 
//cnt表示st[]的状态有多少个1(为了后面利用背包的思想转移) 

inline void get_num(int x){
    int now=0;
    while(x){
        x&=(x-1);
        now++;
    }
    cnt[tot]=now;
}

inline void pre_work(){
    for(int i=0;i<(1<<n);++i)
        if(!(i&(i<<1)))//遇到位运算最好加括号,比如不能写成i&(-i)==0(==优先级比&高) 
            st[++tot]=i,get_num(i);
}

#undef int
int main(){
#define int long long
    #ifdef WIN64 
    freopen("qinfan.txt","r",stdin);
    #endif 
    rd(n),rd(K);
    pre_work();
    rep(i,1,tot)f[1][i][cnt[i]]=1;
    rep(i,2,n)
        rep(j,1,tot)
            rep(jj,1,tot){
                if(st[j]&st[jj] || (st[j]<<1)&st[jj] || (st[j]>>1)&st[jj])continue;
                dwn(k,K,cnt[j])
                    f[i][j][k]+=f[i-1][jj][k-cnt[j]];
            } 
    int ans=0;
    rep(i,1,tot)
        ans+=f[n][i][K];
    printf("%lld
",ans);
    return 0;
}

以上是关于一天一DP计划状压DP的主要内容,如果未能解决你的问题,请参考以下文章

一天一DP计划概率期望DP

HDU4057 Rescue the Rabbit(AC自动机+状压DP)

18.06.03 POJ 4126:DNA 15年程设期末05(状压DP)

BZOJ2595: [Wc2008]游览计划(斯坦纳树,状压DP)

POJ1699 Best Sequence(AC自动机+状压DP)

BZOJ 25952595: [Wc2008]游览计划 (状压DP+spfa,斯坦纳树?)