一道入门的状压dp题,很有意思也很简单。
定义f[i][j]表示第i行的状态为j时,前i行的方案总数,那么答案ans=∑f[n][j].
考虑状态的转移,第i-1行的状态k能转移到第i行的j,当且仅当j&k==0且j,k分别符合他们自己放在那一行的条件,所以f[i][j]=∑f[i-1][k] (条件符合)。
另外,位运算符的优先级很毒瘤,所以最好在运算时多加几个括号来保证运算的正确性。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 typedef long long ll; 6 #define mod 100000000 7 int n,m,a[15],ok[1<<13]; 8 ll f[13][1<<13]; 9 int main() { 10 scanf("%d%d",&n,&m); 11 for(int i=1;i<=n;i++) { 12 for(int j=1,x;j<=m;j++) { 13 scanf("%d",&x); 14 a[i]=a[i]*2+x; 15 } 16 } 17 for(int i=0;i<1<<m;i++) 18 if(!((i&(i<<1))||(i&(i>>1)))) { 19 ok[i]=1; 20 if((i&a[1])==i) f[1][i]=1; 21 } 22 for(int i=2;i<=n;i++) { 23 for(int j=0;j<1<<m;j++) 24 if(ok[j]&&((j&a[i-1])==j)) 25 for(int k=0;k<1<<m;k++) 26 if(ok[k]&&((k&a[i])==k)&&!(j&k)) 27 f[i][k]=(f[i][k]+f[i-1][j])%mod; 28 } 29 ll ans=0; 30 for(int i=0;i<1<<m;i++) 31 ans=(ans+f[n][i])%mod; 32 printf("%lld ",ans%mod); 33 return 0; 34 }