题目地址:POJ 3254
状压水题。
先预处理出每行所有可能出现的情况。然后可以用vector存起来。
然后先处理出第一行所有的情况。然后再从第二行开始不断与上一行进行状态转移,状态转移很简单就不说了。
最后统计出最后一行的个数和就可以了。
代码如下;
#include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #include <stdio.h> using namespace std; #define LL __int64 const int mod=100000000; const int INF=0x3f3f3f3f; int a[20][20]; int dp[3][1<<13]; vector<int>vec[13]; bool Judge(int x, int y, int m) { int i; for(i=0; i<m; i++) { if((x&(1<<i))&&(y&(1<<i))) return 0; } return 1; } int main() { int n, m, i, j, tot, k, h, flag, ans, tmp; scanf("%d%d",&n,&m); for(i=0; i<n; i++) { for(j=0; j<m; j++) { scanf("%d",&a[i][j]); } } tot=1<<m; for(i=0; i<n; i++) { for(j=0; j<tot; j++) { flag=0; for(k=0; k<m; k++) { if(j&(1<<k)) { if(!a[i][k]) { flag=1; break; } if(k>0&&(j&(1<<k-1))) { flag=1; break; } } } if(!flag) vec[i].push_back(j); } } for(i=0; i<vec[0].size(); i++) { dp[0&1][vec[0][i]]=1; } //printf("%d\n",vec[0].size()); ans=0; for(i=1; i<n; i++) { memset(dp[i&1],0,sizeof(dp[i&1])); for(j=0; j<vec[i].size(); j++) { tmp=vec[i][j]; for(k=0; k<vec[i-1].size(); k++) { if(Judge(tmp,vec[i-1][k], m)) { dp[i&1][tmp]+=dp[i-1&1][vec[i-1][k]]; if(dp[i&1][tmp]>=mod) dp[i&1][tmp]%=mod; } } if(i==n-1) { ans+=dp[i&1][tmp]; if(ans>=mod) ans%=mod; //printf("%d\n",ans); } } } if(n==1) { ans=vec[0].size(); } printf("%d\n",ans); return 0; }
POJ 3254 Corn Fields (状压DP+滚动数组)
原文地址:http://blog.csdn.net/scf0920/article/details/42560901