睡前小dp-poj3254-状压dp入门
http://poj.org/problem?id=3254
从这里学的 http://blog.csdn.net/accry/article/details/6607703
状压dp的入门题。一片N×M的田地,有的地方可以种玉米,有的地方不可以。种玉米的区块不能相邻。种玉米的求总方案数,不种玉米也是一种方案。
每一行总共2^N种状态,其中删去有相邻的状态,删除不符合给定条件的状态。保留下最终的所有状态。然后开始dp。
从上往下,每一行之依赖于上一行。所以从上一行转移过去,把状态数加起来就行了。
其中几个函数写的比较精妙,结合二进制运算理解一下并不难。
/*--------------------------------------------------------------------------------------*/ // Helica's header // Second Editions // 2015.11.7 // #include <algorithm> #include <iostream> #include <cstring> #include <ctype.h> #include <cstdlib> #include <cstdio> #include <vector> #include <string> #include <queue> #include <stack> #include <cmath> #include <set> #include <map> //debug function for a N*M array #define debug_map(N,M,G) printf("\n");for(int i=0;i<(N);i++)\ {for(int j=0;j<(M);j++){\ printf("%d",G[i][j]);}printf("\n");} //debug function for int,float,double,etc. #define debug_var(X) cout<<#X"="<<X<<endl; /*--------------------------------------------------------------------------------------*/ using namespace std; const int MOD = 100000000; int N,M,T; int dp[20][1000],state[1000],cur[20]; int cnt; bool ok(int x) { if(x&(x<<1)) return 0; return 1; } bool fit(int s,int c) { if(s&c) return 0; return 1; } int main() { while(~scanf("%d%d",&N,&M)) { for(int i=1;i<=N;i++) { cur[i] = 0; for(int j=1;j<=M;j++) { int a; scanf("%d",&a); if(a==0) cur[i] += (1<<(M-j)); } } cnt=0; for(int i=0;i < 1<<M;i++) if(ok(i)) { state[++cnt] = i; } memset(dp,0,sizeof dp); for(int i=1;i<=cnt;i++) if(fit(state[i],cur[1])) dp[1][i] = 1; for(int i=2;i<=N;i++) { for(int j=1;j<=cnt;j++) { if(!fit(state[j],cur[i])) continue; for(int k=1;k<=cnt;k++) { if(!fit(state[k],cur[i-1])) continue; if(state[j]&state[k]) continue; dp[i][j] = (dp[i][j]+dp[i-1][k])%MOD; } } } int ans = 0; for(int i=1;i<=cnt;i++) ans = (ans+dp[N][i])%MOD; printf("%d\n",ans); } }