POJ 2411 Mondriaan's Dream ——状压DP 插头DP

【题目分析】

用1*2的牌铺满n*m的格子。

刚开始用到动规想写一个n*m*2^m,写了半天才知道会有重复的情况。

So Sad。

然后想到数据范围这么小,爆搜好了。于是把每一种状态对应的转移都搜了出来。

加了点优(gou)化(pi),然后poj上1244ms垫底。

大概的方法就是考虑每一层横着放的情况,剩下的必须竖起来的情况到下一层取反即可。

然后看了 《插头DP-从入门到跳楼》 这篇博客,怒抄插头DP

然后16ms了,自己慢慢YY了一下,写出了风(gou)流(pi)倜(bu)傥(tong)的代码

【代码】

状压DP

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
ll dp[12][1<<12];
int pos[12],n,m,to[1<<12];
void print(int x){F(i,0,m-1)printf("%d",(x>>i)&1);}
void dfs(int x)
{
	if (to[x]) return ;
	to[x]=1;
	F(i,0,m-2)
		if ((!(x&pos[i]))&&(!(x&pos[i+1])))
			dfs(x|pos[i]+pos[i+1]);
}
int main()
{
	while (scanf("%d%d",&n,&m)!=EOF&&n&&m)
	{
		memset(dp,0,sizeof dp); int all=(1<<m)-1;
		F(i,0,m) pos[i]=1<<i; dp[0][(1<<m)-1]=1;
		F(i,0,n-1)
		{
			F(j,0,(1<<m)-1)
			{
				memset(to,0,sizeof to);
				int aim=j^all; dfs(aim);
				F(k,0,(1<<m)-1)
					if (to[k]) dp[i+1][k]+=dp[i][j];
			}
		}
		printf("%lld\n",dp[n][(1<<m)-1]);
	}
}

  插头DP

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;  

long long dp[2][1<<11];  

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m),(n||m))
    {
        int total=1<<m;
        int pre=0,now=1;
        memset(dp[now],0,sizeof(dp[now]));
        dp[now][0]=1;  

        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
        {
            swap(now,pre);
            memset(dp[now],0,sizeof(dp[now]));  

            for(int S=0;S<total;S++) if( dp[pre][S] )
            {
                dp[now][S^(1<<j)]+=dp[pre][S];
                if( j && S&(1<<(j-1)) && !(S&(1<<j)) )
                    dp[now][S^(1<<(j-1))]+=dp[pre][S];
            }
        }  

        printf("%lld\n",dp[now][0]);
    }
}

  自己写的代(gou)码(pi)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define F(i,j,k) for (int i=j;i<=k;++i)
ll dp[2][1<<12];
int n,m;
void print(int x)
{F(i,0,m)printf("%d",(x>>i)&1);}
int main()
{
	while (scanf("%d%d",&n,&m)!=EOF&&n&&m)
	{
		if (n<m) swap(n,m);
		int now=1,pre=0;
		memset(dp[now],0,sizeof dp[now]);
		dp[now][0]=1;
		F(i,0,n-1)
			F(j,0,m-1)
			{
				now^=1;pre^=1;
				memset(dp[now],0,sizeof dp[now]);
				F(s,0,(1<<(m+1))-1) if (dp[pre][s])
				{
					if ((s&(1<<j))&&!(s&(1<<(j+1)))) dp[now][s^(1<<j)]+=dp[pre][s];
					if (!(s&(1<<j))&&!(s&(1<<(j+1)))) dp[now][s^(1<<j)]+=dp[pre][s],dp[now][s^(1<<(j+1))]+=dp[pre][s];
					if (!(s&(1<<j))&&(s&(1<<(j+1)))) dp[now][s^(1<<(j+1))]+=dp[pre][s];
				}
				if (j==m-1)
				{
					now^=1;pre^=1;
					memset(dp[now],0,sizeof dp[now]);
					F(s,0,(1<<m)-1) if (dp[pre][s]&&!(s&(1<<m)))
						dp[now][(s<<1)&((1<<(m+1))-1)]+=dp[pre][s];
				}
			}
		printf("%lld\n",dp[now][0]);
	}
}

POJ 2411 Mondriaan's Dream ——状压DP 插头DP

时间: 2024-10-06 06:32:09

POJ 2411 Mondriaan's Dream ——状压DP 插头DP的相关文章

POJ 2411 Mondriaan&#39;s Dream(状压DP)

http://poj.org/problem?id=2411 求一个n*m矩阵用1*2方块去填满的情况有几种 思路:状压dp,先预处理那些状态之间能互相到达,情况就几种,上一个两个1,下一个状态也两个1,上一个为0,下一个必须为1,还有一种是上一个为1,下一个为0的情况 然后就一层层往后递推即可 代码: #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int

poj 2411 Mondriaan&#39;s Dream 状压dp入门

题意: 求h*w的矩形被1*2的小矩形覆盖的方案数. 分析: 状压dp入门,<挑战程序设计竞赛>上讲的很好,好几天才看懂. 代码: #include <iostream> using namespace std; __int64 ans[16][16]; int n,m; __int64 dp[2][1<<16]; __int64 solve() { int i,j,used; memset(dp,0,sizeof(dp)); __int64 *crt=dp[0],*n

POJ 2411 Mondriaan&#39;s Dream (状压DP)

题意:给出一个n*m的棋盘,及一个小的矩形1*2,问用这个小的矩形将这个大的棋盘覆盖有多少种方法. 析:对第(i,j)位置,要么不放,要么竖着放,要么横着放,如果竖着放,我们记第 (i,j)位置为0,(i+1,j)为1,如果横着放,那么我们记 (i,j),(i,j+1)都为1,然后dp[i][s]表示 第 i 行状态为 s 时,有多少方法,那么我们就可以考虑与和匹配的状态,这个也很容易判断. 代码如下: #pragma comment(linker, "/STACK:1024000000,102

POJ 2411 Mondriaan&#39;s Dream (状压+dfs)

Language: Default Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12405   Accepted: 7239 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in

poj 2411 Mondriaan&#39;s Dream(状压DP)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12232   Accepted: 7142 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

POJ 2411 &amp;&amp; HDU 1400 Mondriaan&#39;s Dream (状压dp 经典题)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12341   Accepted: 7204 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

poj 2411 Mondriaan&#39;s Dream 骨牌铺放 状压dp

题目链接 题意 用\(1\times 2\)的骨牌铺满\(H\times W(H,W\leq 11)\)的网格,问方案数. 思路 参考focus_best. 竖着的骨牌用\(\begin{pmatrix}0\\1\end{pmatrix}\)表示,横着的骨牌用\(\begin{pmatrix}1&1\end{pmatrix}\)表示. 则对于第\(i\)行,与之相容的第\(i-1\)行的状态需满足: 第\(i\)行是0的位置,第\(i-1\)行必须是1: 第\(i\)行是1的位置,第\(i-1\

POJ 2411【题解】Mondriaan&#39;s Dream 状压DP

题目链接:http://poj.org/problem?id=2411 把每一行当作一个二进制状态. 1表示是一个竖着的1*2的方格. 0表示其他状态. 那么显然当i-1的状态k能转移到i的j: 1.j 和 k 的按位与为0.(有1必须要0,0也可以有1) 2.j 和 k 按位或每一段0都有偶数个.(表示横着的长方形) 那么就可以预处理一下合格的点. 然后状压DP. 代码如下: #include<cstdio> using namespace std; int n,m; long long f

poj 2411 Mondriaan&#39;s Dream(状态压缩+dp)

 题意:用1*2砖块铺满n*m的房间. 思路转自:http://www.cnblogs.com/scau20110726/archive/2013/03/14/2960448.html 因为这道题输入范围在11*11之间,所以可以先打表直接输出.......... 状态压缩DP 经典覆盖问题,输入n和m表示一个n*m的矩形,用1*2的方块进行覆盖,不能重叠,不能越出矩形边界,问完全覆盖完整个矩形有多少种不同的方案 其中n和m均为奇数的话,矩形面积就是奇数,可知是不可能完全覆盖的.接着我们来看