状态压缩动态规划,就是我们俗称的状压DP,是利用计算机二进制的性质来描述状态的一种DP方式
常见的用有选或不选(01,二进制),还有丧心病狂的三进制,四进制
首先要熟练运用位运算
1.判断一个数字x二进制下第i位是不是等于1。
方法:if(((1<<(i−1))&x)>0)if(((1<<(i−1))&x)>0)
2.将一个数字x二进制下第i位更改成1。
方法:x=x|(1<<(i−1))x=x|(1<<(i−1))
3.把一个数字二进制下最靠右的第一个1去掉。
方法:x=x&(x−1)
然后是枚举子集,补集等
首先是一道打基础的题
枚举,只是用到了位运算,好像不算状压
#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; }
很明显的状压,先预处理第一行的状态,枚举后面的状态,对于每个状态,又枚举前一行的状态是否合法
太暴力了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; }