POJ 3254 Corn Fields状态压缩DP
下面有别人的题解报告,并且不止这一个状态压缩题的哦····
http://blog.csdn.net/accry/article/details/6607703
下面是我的代码,代码很挫,绝对有很大的优化的空间····
1 #include <cstdio> 2 #include <cstring> 3 int dp[2][(1 << 12) + 2]; 4 //检查一行的奶牛放置情形是否合理 5 //即是否有相邻的两个1,没有返回true 6 bool checkHori(int state) 7 { 8 if(!(state & (state << 1)) ) return true; 9 else return false; 10 } 11 12 //检查竖直方向的奶牛放置情形是否合理 13 //即是否竖直方向有相同的1 14 bool checkVert(int a,int b) 15 { 16 if(!(a&b)) return true; 17 else return false; 18 } 19 20 //看该位置是否是肥沃的土地 21 //关系式自己推出来 22 bool checkPos(int map,int state) 23 { 24 if( (map| state) == map) return true; 25 else return false ; 26 } 27 28 //该算法时间复杂度很高,为O(m*2^(2*n)) 29 //最坏情况下为O(12*2^24),10^8左右,一定是可以改进的 30 int main() 31 { 32 freopen("in.cpp","r",stdin); 33 int m,n; 34 scanf("%d%d",&m,&n); 35 memset(dp,0,sizeof(dp)); 36 dp[0][0] = 1; 37 int x=0; 38 for(int i=1; i<=m; ++i) 39 { 40 int t,tmp=1,map =0; //map用来记录第i行土地的土壤状态 41 for(int d=0; d<n ; ++d) 42 { 43 scanf("%d",&t); 44 map += t*tmp; 45 tmp *=2; 46 } 47 x =1-x; 48 for(int j=0; j< (1 << n); ++j) 49 dp[x][j] = 0; //滚动数组,用时间换空间 50 for(int j=0; j< (1 << n); ++j) 51 { 52 for(int k=0; k < (1 << n); ++k) 53 { 54 if( checkHori(k) && checkPos(map,k) && (i == 1 || checkVert(k,j) ) ) 55 dp[x][k] += dp[1-x][j]; 56 } 57 } 58 } 59 int ans=0; 60 for(int i=0; i< (1 << n); ++i) 61 { 62 ans += (dp[x][i] % 100000000); 63 ans %= 100000000; 64 } 65 printf("%d\n",ans); 66 return 0; 67 }
通过计算得出,当n = 12时,2^12 = 4096,而一行能成功放置的方法数仅为377,
由此可先预处理,离散化存储,极大地降低复杂度。新的算法的复杂度最坏情况下为12*377*377,大概为10^6的复杂度。
1 #include <cstdio> 2 #include <cstring> 3 int dp[2][400]; 4 int st[400]; 5 //检查一行的奶牛放置情形是否合理 6 //即是否有相邻的两个1,没有返回true 7 bool checkHori(int state) 8 { 9 if(!(state & (state << 1)) ) return true; 10 else return false; 11 } 12 13 //检查竖直方向的奶牛放置情形是否合理 14 //即是否竖直方向有相同的1 15 bool checkVert(int a,int b) 16 { 17 if(!(a&b)) return true; 18 else return false; 19 } 20 21 //看该位置是否是肥沃的土地 22 //关系式自己推出来 23 bool checkPos(int map,int state) 24 { 25 if( (map| state) == map) return true; 26 else return false ; 27 } 28 29 int init(int n) 30 { 31 int num=0; 32 for( int i=0; i<(1<<n); ++i ) 33 { 34 if(checkHori(i)) 35 { 36 st[num++] = i; 37 } 38 } 39 return num; 40 } 41 int main() 42 { 43 // freopen("in.cpp","r",stdin); 44 int m,n; 45 scanf("%d%d",&m,&n); 46 int num=init(n); 47 memset(dp,0,sizeof(dp)); 48 dp[0][0] = 1; 49 int x=0; 50 for(int i=1; i<=m; ++i) 51 { 52 int t,tmp=1,map =0; //map用来记录第i行土地的土壤状态 53 for(int d=0; d<n ; ++d) 54 { 55 scanf("%d",&t); 56 map += t*tmp; 57 tmp *=2; 58 } 59 x =1-x; 60 for(int j=0; j< num; ++j) 61 dp[x][j] = 0; //滚动数组,用时间换空间 62 for(int j=0; j< num; ++j) 63 { 64 for(int k=0; k < num; ++k) 65 { 66 if(checkPos(map,st[k]) && (i == 1 || checkVert(st[k],st[j]) ) ) 67 dp[x][k] += dp[1-x][j]; 68 } 69 } 70 } 71 int ans=0; 72 for(int i=0; i< num; ++i) 73 { 74 ans += (dp[x][i] % 100000000); 75 ans %= 100000000; 76 } 77 printf("%d\n",ans); 78 return 0; 79 }