POJ 2411 Mondriaan's Dream 解题报告【动态规划】(代码部分)

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

 

long long dp[12][3000];

//用0代表横放或竖放的上部,1代表竖放的下部,每行是一个二进制数(<2048)

int main()

{

         long long h,w,ans,i,j,k,tmp1,tmp2,l,c,cs;

         scanf("%lld",&cs);

         while(cs--)

         {

                   scanf("%lld%lld",&h,&w);

                   if(h*w&1) {printf("0\n"); continue;}

                   if(w>h){tmp1=h; h=w; w=tmp1;}//h*2^w的数量级,因此让w为小的那个

                   memset(dp,0,sizeof(dp));

                   tmp1=w; l=1; while(tmp1--) l*=2;

                   for(i=0;i<l;i++)

                   {//得到第一行可能的情况,并赋值1

                            tmp1=i; c=w;

                            while(c)

                            {

                                     if(tmp1&1) tmp1>>=1,c--;

                                     else if(tmp1&3) break;

                                     else if(c<2) break;

                                     else tmp1>>=2,c-=2;

                            }

                            if(!c) dp[0][i]=1;

                   }

                   for(i=1;i<h;i++)

                   {//依次递推加和

                            for(j=0;j<l;j++)

                            {//对每行的每一个状态递加底层的相容状态

                                     for(k=0;k<l;k++)

                                     {//寻找相融状态并递加

                                               tmp1=j; tmp2=k; c=w;

                                               while(c)

                                               {

                                                        if(tmp2&1)

                                                        {

                                                                 if(tmp1&1) break;

                                                                 else tmp1>>=1,tmp2>>=1,c--;

                                                        }

                                                        else

                                                        {

                                                                 if(tmp1&1) tmp1>>=1,tmp2>>=1,c--;

                                                                 else if(c<2||(tmp1&3)||(tmp2&3)) break;

                                                                 else tmp1>>=2,tmp2>>=2,c-=2;

                                                        }

                                               }

                                               if(!c) dp[i][j]+=dp[i-1][k];

                                     }

                                     if(i==h-1) break;//最上层必全为0,找到为0的情况即是结果

                            }

                   }

                   printf("%lld\n",dp[h-1][0]);

         }

         return 0;

}

posted on 2010-03-05 10:28  liugoodness  阅读(604)  评论(0编辑  收藏  举报

导航