我的第一道状态压缩DP , 题目还是很水的,
题意是再N*M的方格上,每个方格给出0 1两种状态,1是可放物品,0是不可放,问有多少种物品不相邻放置的情况,属于经典的状态压缩模型,注意下位运算的技巧,还有就是边界处理,对第一行的处理,因为这个WA了2次。
题解参考http://bbs.cfan.com.cn/thread-1170262-1-1.html
多用一些位运算小技巧,是减少状态压缩DP代码量的很好方法
#include <cstdio> #include <cstring> const int mod=100000000; int map[14]; int dp[14][1<<13]; bool valid[1<<13]; int n,m; inline bool cannot(int x)//左移一位后与原数相与 ,为0时可行 { return (x<<1)&x; } void init () { memset (valid , true , sizeof(valid)); for (int i=0 ; i<(1<<13) ; ++i) { if(cannot(i))valid[i]=false; } } /*bool checkonmap (int row ,int k) { for (int i=0 ; i<m ; ++i,k>>=1) { if(!map[row][i] && (k&1))return false; } return true; }*/ void debug () { for (int i=0 ; i<n ; ++i) { for (int j=0 ; j<(1<<m) ; ++j) printf("%d ",dp[i][j]); printf("\n"); } } int main () { init (); int t; while (~scanf("%d%d",&n,&m)) { int ans=0; for (int i=0 ; i<n ; ++i) { map[i]=0; for (int j=0 ; j<m ; ++j) { scanf("%d",&t); if(!t)map[i]+=1<<j; } } memset (dp , 0 , sizeof(dp)); for (int i=0 ; i<n ; ++i) { for (int j=0 ; j<(1<<m) ; ++j) { if(!valid[j])continue; if(!i){if(!(map[i]&j))dp[i][j]=1; continue;} for (int k=0 ; k<(1<<m) ; ++k) { if(!valid[k])continue; if(j&k)continue; if(!(map[i]&j))dp[i][j]=(dp[i-1][k]+dp[i][j])%mod; } } } //debug(); for (int i=0 ; i<(1<<m) ; ++i) ans=(dp[n-1][i]+ans)%mod; printf("%d\n",ans); } return 0; }