poj2411 Mondriaan's Dream(状压dp)

来源:互联网 发布:java随机数生成 编辑:程序博客网 时间:2024/06/06 19:02

Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series' (where he had to use his toilet paper to draw on, for all of his paper was filled with squares and rectangles), he dreamt of filling a large rectangle with small rectangles of width 2 and height 1 in varying ways. 

Expert as he was in this material, he saw at a glance that he'll need a computer to calculate the number of ways to fill the large rectangle whose dimensions were integer values, as well. Help him, so that his dream won't turn into a nightmare!
Input
The input contains several test cases. Each test case is made up of two integer numbers: the height h and the width w of the large rectangle. Input is terminated by h=w=0. Otherwise, 1<=h,w<=11.
Output
For each test case, output the number of different ways the given rectangle can be filled with small rectangles of size 2 times 1. Assume the given large rectangle is oriented, i.e. count symmetrical tilings multiple times.
Sample Input
1 21 31 42 22 32 42 114 110 0
Sample Output
10123514451205

都在代码里了。

/**    *我们一行一行的放,实际上影响当前行的是上一行的竖直放的格子    *那么我们可以枚举竖直放的状态,然后去搜索可以横着放置的方案数,然后乘上到上一行(上一行竖直位置相同)为止的方案数即可(下面体现的是每次加)    *二进制表示当前行的放置状态0表示没放,也就是当前块要竖着放,1表示已经横着放了    *那么对于下一行,搜索的时候对状态取一个反就可以了。(太巧妙了)**/#include <cstdio>#include <cstring>using namespace std;typedef long long LL;int n,m;LL dp[15][1<<11];LL temp;//搜索当前i行横着放的种类数//i表示行,state表示当前状态为state,位置为k//当前状态的位置为1表示横着放了,为0表示竖着放。//所以每次dp之前对状态取一个反void dfs(int i,int state,int k){    if(k >= m)    {        dp[i][state] += temp;        return ;    }    dfs(i,state,k+1);    if(k<=m-2 && !(state&1<<k) && !(state&1<<(k+1)))dfs(i,state|1<<k|1<<(k+1),k+2);}int main(){    while(~scanf("%d%d",&n,&m)&&n)    {        //如果都为奇数肯定是不存在的        if(n&1 && m&1)        {            puts("0");            continue;        }        memset(dp,0,sizeof dp);        //一开始temp肯定为1        temp = 1;        //先搜索第一行        dfs(0,0,0);        //枚举剩余的行        for(int i = 1; i < n; ++i)        {            //枚举状态            for(int j = 0; j < 1<<m; ++j)            {                //记录到上一行为止的方案数                if(dp[i-1][j])temp = dp[i-1][j];                else continue;                //搜索当前行可以摆放的方案数                dfs(i,j^((1<<m)-1),0);            }        }        printf("%I64d\n",dp[n-1][(1<<m)-1]);    }    return 0;}





原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 孩子计算总出错怎么办 初三计算题算错怎么办 孩子口算老出错怎么办 孩子考试总粗心怎么办 孩子作业错误率高怎么办 数学计算总出错怎么办 16岁不认字怎么办 数学细节丢分怎么办 感觉自己老了怎么办 小学拼音不过关怎么办 小学面试不过关怎么办 小学阅读不过关怎么办 孩子计算老出错怎么办 工作中总是马虎怎么办 孩子总是计算错误怎么办 做设计老是犯错怎么办 小学生阅读总出错怎么办 写作文没思路怎么办 孩子不爱写作文怎么办 写作文没有素材怎么办 写作文没有灵感怎么办 做事工作马虎粗心大意怎么办 小孩作业马虎粗心大意怎么办 孩子写字一直错怎么办 孩子写字老错怎么办 写错字涂黑了怎么办 写错字不能涂改怎么办 孩子爱写错别字怎么办 孩子读题马虎怎么办 孩子知错不该怎么办 小孩胆小反应慢怎么办 孩孑经常流鼻血怎么办 中考考号写错了怎么办 头后仰就头晕怎么办 感觉自己要晕倒怎么办 孩子不愿动手写字怎么办 老年人恶心想吐怎么办 小学生老写错别字怎么办 突然头晕站不稳 怎么办 早上起床突然天旋地转怎么办 躺着突然感觉天旋地转怎么办