POJ2663

来源:互联网 发布:淘宝买家好评率100% 编辑:程序博客网 时间:2024/06/06 02:12

POJ2663 Tri Tiling

现在给出一个3*n(0<=n<=30)的矩阵,要求用1*2的骨牌来填充,问有多少种填充方式?

分析:

解法一:

首先这道题n的规模比较小我先试下用轮廓线DP来解。

(轮廓线DP见:http://blog.csdn.net/u013480600/article/details/19499899)

注意POJ的这道题目测试数据当n==0时输出的是1,否则WA。

AC代码:47MS

#include<cstdio>#include<algorithm>#include<cstring>using namespace std;const int maxn = 15;long long d[2][1<<maxn];int n,m,cur;void update(int a,int b)//a是包含m位1进制数的老状态,b是包含m+1位1进制数的新状态{    if(b&(1<<m)) d[cur][b^(1<<m)] += d[1-cur][a];//只有新轮廓线首位为1时才更新}int main(){    while( scanf("%d",&n)==1&&n>=0 )    {        //if(m>n)swap(n,m);        m=3;        memset(d,0,sizeof(d));        cur=0;        d[cur][(1<<m)-1]=1;        for(int i=0;i<n;i++)            for(int j=0;j<m;j++)            {                cur ^=1;                memset(d[cur],0,sizeof(d[cur]));                for(int k=0;k<(1<<m);k++)//k的二进制形式表示前一个格子的轮廓线状态                {                    update(k,k<<1);//当前格不放,直接k左移一位就表示带m+1位的新轮廓线的状态                    if(i && !(k&(1<<(m-1)) )) update(k,(k<<1)^(1<<m)^1);//上放,要求轮廓线首为0                    if(j && (!(k&1)) ) update(k,(k<<1)^3);//左放,要求轮廓线尾0,首1                }            }        printf("%I64d\n",d[cur][(1<<m)-1]);    }    return 0;}


解法二:递推法。

由于本题的矩阵只有3列,所以可以推断出,该矩阵必定由且仅由3*2,3*4,…3*m(m为偶数)的不可分割的小矩阵构成。如下:

 等等。还有2*6,2*8的矩阵没有画出来,可以自己想想如何构成不可分割的2*6小矩阵。且可以推断2*m(m>=4且为偶数)的不可分割小矩阵数目都是2.想想为什么?

    所以可以得到计算a[n](表示3*n的矩阵有多少摆放方式)的递推公式:

a[n]=a[n-2]*3+a[n-4]*2+a[n-6]*2+….初始值为a[0]=1且其他a[n]初始时都为0。

AC代码:0MS

//利用递推的公式求解#include<cstdio>#include<cstring>using namespace std;const int maxn = 35;int n;long long a[maxn];int main(){    memset(a,0,sizeof(a));    a[0]=1;    a[2]=3;    for(int i=4;i<31;i+=2)    {        int j=4;        a[i] +=a[i-2]*3;        while(j<=i)        {            a[i]+=a[i-j]*2;            j+=2;        }    }    while(scanf("%d",&n)==1&&n>=0)    {        printf("%I64d\n",a[n]);    }    return 0;}

解法三:利用兼容模式队求解状态压缩DP。

(兼容模式状态压缩DP见:http://blog.csdn.net/u013480600/article/details/19569291)

直接把原题的m该成3,然后注意读入的格式即可。

AC代码:0ms

//兼容模式队求解状态压缩DP#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn = 35;//最大行数const int maxm = 16*16;//兼容模式对的最大数目int n,m,w;long long d[maxn][1<<4];int path[maxm][2];void dfs(int c,int pre,int now){    if(c>m)return ;    else if(c==m)    {        path[w][0]=pre;        path[w++][1]=now;        return ;    }    dfs(c+1,(pre<<1)|1,now<<1);//不放    dfs(c+1,(pre<<1),(now<<1)|1);//上放    dfs(c+2,(pre<<2)|3,(now<<2)|3);//右放}int main(){    while(scanf("%d",&n)==1&&n>=0)    {        m=3;        w=0;        dfs(0,0,0);        memset(d,0,sizeof(d));        d[0][(1<<m)-1]=1;        for(int i=0;i<n;i++)            for(int j=0;j<w;j++)                d[i+1][path[j][1]] += d[i][path[j][0]];        printf("%I64d\n",d[n][(1<<m)-1]);    }    return 0;}


0 0
原创粉丝点击