dp专辑F - Mondriaan's Dream [dp+dfs]

来源:互联网 发布:广州餐饮数据分析 编辑:程序博客网 时间:2024/05/22 11:32

转自:http://hi.baidu.com/newmyl/blog/item/b1d3c609fd6009206b60fbb1.html


      当高度和宽度都为奇数时显然答案为0, 这个用面积的奇偶性就很容易得证

f[i][s1]为第i-1行全满且第i行状态为s1时的种数,便有如下递推关系:

f[i][s1] = sigma(f[i-1][s2]);
其中(s1, s2)整体作为一个放置方案, 这样f[h+1][0]即是答案了

      对于每一个位置,我们有三种放置方法:

1.       竖直放置

2.       水平放置

3.       不放置

d为当前列号 ,初始化d, s1, s2都为0;对应以上三种放置方法,s1, s2的调整为:

1. d = d + 1, s1 << 1 | 1, s2 << 1;

2. d = d + 2, s1 << 2 | 3, s2 << 2 | 3;

3. d = d + 1, s1 << 1,   s2 << 1 | 1;

先就第一种情况解释一下,另外的两种情况可以类推

S1<<1|1即为把s1的二进制表示后面加上一个1,对就于本题来说就是(d+1)列上放

置,s2<<1即为把s2的二进制表示后面加上一个0,对于本题来说就是(d+1)列上不放置。

       但为什么s1s2会如此变化呢?本人在此处想了好长时间,后来想明白了,s1对应于本行的状态,s2对应于上一行的状态,能竖直放置意味着上一行的(d+1)列是空着的,因此此时上一行的状态为s2<<1,同时竖置放置了之后,则本行(d+1)行放置了东西,状态于是变为s1<<1|1;

d = w时保存状态

对于初始时的f值,可以假设第0行全满,第一行只有两种放法:

1. 水平放置 d = d + 2, s << 2 | 3;
       2. 
不放置   d = d + 1, s << 1;
另外,利用滚动数组,可以减少空间的开销

还有一个可以提高较率的地方,当输入的 w > h 时,对调,因为横向的运算是指数

级的, 而列向的是线性的.


# include <stdio.h># include <string.h>__int64 a[2][3000];int t,n,m;void dfs(int d,int mm){    if(d==m)    {        a[0][mm]++;        return;    }    if(d+1<=m)        dfs(d+1,mm<<1);    if(d+2<=m)        dfs(d+2,mm<<2|3);}void DFS(int d,int mm,int nn)//mm对应于上一行状态,nn对应于下一行状态{    if(d==m)    {        a[t][nn]+=a[(t+1)%2][mm];        return;    }    if(d+1<=m)    {        DFS(d+1,mm<<1,nn<<1|1);        DFS(d+1,mm<<1|1,nn<<1);    }    if(d+2<=m)        DFS(d+2,mm<<2|3,nn<<2|3);}int main(){    int i;    while(scanf("%d%d",&n,&m)&&n&&m)    {        if((n*m)%2)        {            printf("0\n");            continue;        }        if(n>m)            n^=m,m^=n,n^=m;        memset(a,0,sizeof(a));        dfs(0,0);        for(i=2; i<=n; i++)        {            t=(i+1)%2;            DFS(0,0,0);            memset(a[(t+1)%2],0,sizeof(a[0]));        }        printf("%I64d\n",a[(n+1)%2][(1<<m)-1]);    }    return 0;}

别附打表代码:


# include <stdio.h>__int64 a[11][11]={0,1,0,1,0,1,0,1,0,1,0,1,2,3,5,8,13,21,34,55,89,144,0,3,0,11,0,41,0,153,0,571,0,1,5,11,36,95,281,781,2245,6336,18061,51205,0,8,0,95,0,1183,0,14824,0,185921,0,1,13,41,281,1183,6728,31529,167089,817991,4213133,21001799,0,21,0,781,0,31529,0,1292697,0,53175517,0,1,34,153,2245,14824,167089,1292697,12988816,108435745,1031151241,8940739824,0,55,0,6336,0,817991,0,108435745,0,14479521761,0,1,89,571,18061,185921,4213133,53175517,1031151241,14479521761,258584046368,3852472573499,0,144,0,51205,0,21001799,0,8940739824,0,3852472573499,0};int main(){int n,m;while(scanf("%d%d",&n,&m)&&n&&m)   printf("%I64d\n",a[n-1][m-1]);return 0;}


原创粉丝点击