POJ 3254 Corn Fields 状压DP
题意:给出N*M的01矩阵(N<12&&M<12),0不可以种草,1可以种草,要求种的草不能相邻(不可以共享一个边),问有多少种种法
第一道状压DP,应该来说不算难,看了这个博客,受益很大 http://www.cnblogs.com/ka200812/archive/2011/08/11/2135607.html
注:DFS的话,2的次方级,会爆的。 由题目的特点,下一行只受上一行的影响,而且还有重复计算(下一行的某一状态的数量由上一行得来),说的那么乱呢,
看连接的博客吧,讲的真不错
1.判断一个二进制数有没有相邻的两位同为1的方法 i&(1<<1)||i&(i>>1) 位运算的优先级比较低,一般加()
2.判断两个二进制的数有没有相同位上都为1 直接相与 。 为了方便,代码中还把输入翻了过来,1变成0,0变成1,为了Get_state()里面找状态方便...
代码(带预处理的 0MS):
/*
vector
vetor<int>num[];
num[i].clear();
num[i].push_back();
num[i].size();
num[i][j]
*/
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<vector> #define MOD 100000000 #define ll __int64 using namespace std; int state[13][8192]; ll dp[13][8192]; vector<int>num[13]; int r,c; void Get_state(int row,int temp) { num[row].clear(); for(int i=0;i<(1<<c);i++) { if(i&(i>>1)||i&(i<<1)) continue; if(i&temp) continue; num[row].push_back(i); } } int main() { int i,j,k; int temp; while(~scanf("%d%d",&r,&c)) { for(i=0;i<r;i++) { temp=0; for(j=0;j<c;j++) { scanf("%d",&k); k=1-k; temp=(temp<<1)+k; } Get_state(i,temp); } memset(dp,0,sizeof(dp)); for(i=0;i<num[0].size();i++) dp[0][i]=1; for(i=1;i<r;i++) { for(j=0;j<num[i].size();j++) { for(k=0;k<num[i-1].size();k++) { if(num[i][j]&num[i-1][k]) continue; dp[i][j]+=dp[i-1][k]; } } } int ans=0; for(i=0;i<num[r-1].size();i++) { ans=(ans+(dp[r-1][i]%MOD))%MOD; } printf("%d\n",ans); } return 0; }
没有预处理的,dfs枚举每一行
代码(16MS):
#include<iostream> #include<cstdio> #include<cstring> #include<string> #define nMAX 13 #define ll __int64 #define MAX (1<<12) #define MOD 100000000 using namespace std; ll dp[nMAX][MAX+2]; int map[nMAX][nMAX]; int r,c,i,j; void dfs(int col,int state) { if(col==c) {dp[i+1][state]+=dp[i][j]; return ;} if(map[i+1][col]==0) {dfs(col+1,state); return ;}//不可以放 if(j&(1<<col)) //上一行放了,不可以放 { dfs(col+1,state); } else { if(col==0) dfs(col+1,state+(1<<col)); else if((state&(1<<(col-1)))==0) dfs(col+1,state+(1<<col));//以后涉及位运算的都加()就是了 dfs(col+1,state); } } int main() { int k; while(~scanf("%d%d",&r,&c)) { for(i=1;i<=r;i++) //空出一行 for(j=0;j<c;j++) scanf("%d",&map[i][j]); memset(dp,0,sizeof(dp)); dp[0][0]=1; for(i=0;i<r;i++) { for(j=0;j<(1<<c);j++) { if(dp[i][j]) dfs(0,0);//0 0表示i+1行左边起第0个,状态为0 } } int ans=0; for(i=0;i<(1<<c);i++) { ans=(ans+dp[r][i])%MOD; } printf("%d\n",ans); } return 0; }