状压dp学习

状态压缩动态规划,就是我们俗称的状压DP,是利用计算机二进制的性质来描述状态的一种DP方式

常见的用有选或不选(01,二进制),还有丧心病狂的三进制,四进制

首先要熟练运用位运算

1.判断一个数字x二进制下第i位是不是等于1。

方法:if(((1<<(i1))&x)>0)if(((1<<(i−1))&x)>0)

2.将一个数字x二进制下第i位更改成1。

方法:x=x|(1<<(i1))x=x|(1<<(i−1))

3.把一个数字二进制下最靠右的第一个1去掉。

方法:x=x&(x1)

然后是枚举子集,补集等

首先是一道打基础的题

关灯问题II 

枚举,只是用到了位运算,好像不算状压

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const int inf=0x3f;
inline int read(){
    int x=0,k=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') k=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return k*x;
}
int a[105][15],f[1030];
int main(){
//    freopen(".in","r",stdin);
//    freopen(".out","w",stdout);
    int n,m;
    memset(f,127,sizeof(f));
    n=read();m=read();
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            a[i][j]=read();

    f[(1<<n)-1]=0;
    for(int i=(1<<n)-1;i>=0;i--){
        for(int j=1;j<=m;j++){
            int now=i;
            for(int k=1;k<=n;k++){
                if(!a[j][k]) continue;
                else if(a[j][k]==1&&((1<<(k-1))&i)) now^=(1<<(k-1));
                else if(a[j][k]==-1&&!((1<<(k-1))&i)) now^=(1<<(k-1));
            }
            f[now]=min(f[now],f[i]+1);
        }
    }
    if(f[0]==2139062143) cout<<"-1";
    else cout<<f[0];
    return 0;
}
View Code

[USACO06NOV]玉米田Corn Fields

很明显的状压,先预处理第一行的状态,枚举后面的状态,对于每个状态,又枚举前一行的状态是否合法

太暴力了qnq

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const int mod=1e8;
inline int read(){
    int x=0,k=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') k=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return k*x;
}
int dp[15][4100],map[15],a[15][15];
bool pd[4100];
int main(){
//    freopen(".in","r",stdin);
//    freopen(".out","w",stdout);
    int n,m;
    ll ans=0;
    n=read();m=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            a[i][j]=read();
            map[i]=(map[i]<<1)+a[i][j];
        }
    for(int i=0;i<=(1<<m)-1;i++){
        if((((i>>1)&i)==0)&(((i<<1)&i)==0)){
            pd[i]=1;
        }
    }
    for(int i=0;i<=(1<<m)-1;i++){
        if(pd[i]&((i&map[1])==i)){
            dp[1][i]=1;
        }
    }
    for(int i=2;i<=n;i++)
        for(int j=0;j<=(1<<m)-1;j++){
            if(pd[j]&(j&map[i])==j){
                for(int k=0;k<=(1<<m)-1;k++){
                    if((k&j)==0) dp[i][j]=(dp[i][j]+dp[i-1][k])%mod;
                }
            }
        }
    for(int i=0;i<=(1<<m)-1;i++){
        ans=(ans+dp[n][i])%mod;
    }
    cout<<ans;
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/silent-pyb/p/9820402.html