标签:填满 Mondriaan 状压 方块 include Dream ll dp
Mondriaan's Dream(状压dp)
题目大意:用1x2的方块填满NxM的大矩形,问填满的方法有多少种。
解题思路:利用先填好竖着的方块,剩下的空格再用横着的来填,且要求填好竖着的方块时,每一行都要能用横着的方块填满(即连续的空出来的位置必须是偶数,即合法)
AC代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#define ll long long
using namespace std;
const int maxn=12;
ll dp[maxn][1<<maxn];//后面的表示的是,这一行会向下一行突出的状态
bool ap[1<<maxn];
vector<int> st[1<<maxn];
int main(void)
{
int N,M;
while(~scanf("%d %d",&N,&M)&&(N||M))
{
if(N*M%2)//可以先排除一些,面积必须是偶数
{
puts("0");
continue;
}
for(int i=0;i<(1<<M);i++)//处理每一行该有的状态,就是合法的状态,每一行空出来的都必须是偶数
{
int sum=0;
for(int j=0;j<M;j++)
{
if(i&(1<<j))//遇到了没空的,检查空的是否为偶数
{
if(sum&1)
{
ap[i]=false;
break;
}
sum=0;
}else sum++;
}
if(sum&1)ap[i]=false;//要看看剩下来空的是否为偶数
else ap[i]=true;
}
for(int j=0;j<(1<<M);j++)//预处理,由于题目有多组测试样例,可能会超时,所以要预处理
{//每一行突出的状态可以更新出什么状态
st[j].clear();//注意多组测试样例
for(int k=0;k<(1<<M);k++)
{
if((j&k)||!ap[j|k])continue;
st[j].push_back(k);
}
}
memset(dp,0,sizeof(dp));//注意多组测试样例
dp[0][0]=1;
for(int i=1;i<=N;i++)
for(int j=0;j<(1<<M);j++)
for(int k=0;k<st[j].size();k++)
dp[i][j]+=dp[i-1][st[j][k]];
cout<<dp[N][0]<<endl;//最后一行向后面一行突出的要为0
}
return 0;
}
标签:填满,Mondriaan,状压,方块,include,Dream,ll,dp 来源: https://www.cnblogs.com/WUTONGHUA02/p/16684932.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。