POJ 2411 Mondriaan's Dream 状态压缩 搜索
题意:
求用1 * 2 的矩行拼h * w的矩阵方法数(h,w <=11)
算法:
1.朴素算法,根据关系,枚举
由于在做第i行dp时必须完全覆盖第i-1行,只要抓住这个条件不放就行。
1、如果第i行中有0,则第i-1行一定为1;
2、如果第i行中为1的x列第i-1行为0,说明第i行肯定是竖着放的;
3、如果第i行中为1的x列第i-1行的该列也为1,可能性只有一个,第i行是横放的,所以第i行的x+1列也必须为1,又因为第i行的x+1列为1是因为横着放的,所以第i-1行的x+1列也必须为1。
View Code
//自己没写枚举暴力的代码了,速度很慢2000ms,代码来自 //http://gisyhy.blog.163.com/blog/static/129390343200992441558735/ #include <iostream> using namespace std; #define N 11+1 #define S (1<<12) #define LL long long LL dp[N][S]; bool a[S]; int n,Maxn,h,w; bool Ok(int i)//初始化第1行状态为i时是否容许 { for(int k = 0 ; k < w; ) { if(i & (1<<k)) { if(k == w-1 || !(i & (1<<(k+1)))) return false; k+= 2; } else k ++; } return true; } bool Pk(int i,int j)//判断i和j状态有无冲突 { int k; for(k = 0; k < w; ) { if((i & (1<<k)) == 0) { if((j & (1<<k)) == 0)//如果第i行为0,则第j行一定得为1 return false; k ++; } else { if(j & (1<<k)) if(k == w-1 || ((i & (1<<(k+1))) && (j & (1<<(k+1)))) == 0)//我就是在这里倒的霉 //k == w-1 || ((i & (1<<(k+1))) || (j & (1<<(k+1))))这样就少考虑了一种情况,哎呀,不爽!! return false; else k +=2; else k++; } } return true; } int main() { while(scanf("%d %d",&h,&w),h && w) { int i,j,k; if(h < w)//将状态数取小,优化处理 i = h ,h = w,w =i; Maxn = (1<<w)-1; memset(dp,0,sizeof(dp)); for(i = 0 ; i <= Maxn; i++)//初始化第1行 { if(Ok(i)) dp[h][i] =1; } for(k = h-1 ; k >=1; k --)//枚举第k行 { for(i = 0 ; i <= Maxn; i++)//当前行的状态 { for(j = 0; j <= Maxn ;j++)//前一行的状态 { if(Pk(i,j)) dp[k][i] +=dp[k+1][j]; } } } cout<<dp[1][Maxn]<<endl; } return 0; }
2.DFS搜索(奇妙)
View Code
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<algorithm> using namespace std; __int64 dp[2][4100], cow; /* 状态1表示放了,0表示没有放 1. 竖直放置 (上行该列状态为0,当前行该列状态为1) 2. 横着放置 上行该两列状态为1, 此行该两列状态为1 3. 不放 //上行该列状态为1,当前行该列状态为0 */ void DFS( int c, int s1, int s2, int m) //s1当前行状态, s2上一行状态 { if( c > m ) return; if( c == m ) { dp[cow%2][s1] += dp[(cow-1)%2][s2]; return; } DFS(c + 1, (s1<<1)|1, s2<<1, m ); //竖直放置 DFS(c + 1, s1<<1, s2<<1|1, m); //不放 DFS(c + 2, (s1<<2)|3, (s2<<2)|3, m); //横着放置 } void DFS_First(int c, int s1, int m) { if( c > m) return; if( c == m ) { dp[1][s1]++; return; } DFS_First(c + 1, s1<<1, m); //不放 DFS_First(c + 2, (s1<<2)|3, m); //横着放置 } int main( ) { int N, M; while( scanf("%d%d",&N,&M), N && M) { if( (N * M) % 2 ) { puts("0"); continue; } if( N > M ) swap(N, M); memset(dp, 0, sizeof(dp)); DFS_First(0, 0, M); for( cow = 2; cow <= N ; cow++) { DFS(0, 0, 0, M); memset(dp[(cow-1)%2], 0, sizeof(dp[0])); } printf("%I64d\n", dp[N % 2][(1<<M) - 1]); } return 0; }
posted on 2012-08-06 17:23 more think, more gains 阅读(179) 评论(0) 编辑 收藏 举报