首页 > 代码库 > POJ 2411 状压DP经典
POJ 2411 状压DP经典
Mondriaan‘s Dream
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 16771 | Accepted: 9683 |
Description
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!
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 2 1 3 1 4 2 2 2 3 2 4 2 11 4 11 0 0
Sample Output
1 0 1 2 3 5 144 51205
Source
Ulm Local 2000
第一次做状压题目,没怎么优化就是暴力递推。
对于每个格子我们有这么两种可能:
第一,这个格子被竖着的砖块覆盖
第二,这个格子被横着的砖块覆盖
我们不妨用0/1来表示这个状态,0表示这是一个竖着放置的砖块的上方部分,1表示横向覆盖或者被上方竖着覆盖。
之所以用0表示竖放的上方是因为竖着放会对下一行的放置造成影响,而横着放显然不会,我们在放置下一行的时候需要知道上一行的状态才可,
所以遇见上一行这个位置是0就表示这个格子已经被覆盖了的状态,利用这个来判断冲突放置。
(显然每个格子都要被覆盖,我们如果用01表示覆盖与非覆盖的状态显然是无意义的,要从放置方式着手,这一点当时想了好久= =)
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
LL dp[2][2050];
LL ans[15][15];
bool check(int x,int i)
{ return x&(1<<i); }
bool comp(int A,int B,int N)
{
int i=0,j,k;
while(i<N){
if(!check(A,i)){
if(!check(B,i)) return 0;
i++;
}
else{
if(!check(B,i)) i++;
else {
if(i==N-1||!check(A,i+1)||!(check(A,i+1)&&check(B,i+1))) return 0;
else i+=2;
}
}
}
return 1;
}
void solve(int N,int M)
{
if(ans[N][M]+1) {printf("%lld\n",ans[N][M]);return;}
memset(dp,0,sizeof(dp));
dp[0][(1<<N)-1]=1;
int cur=1;
for(int i=1;i<=M;++i){
for(int j=0;j<(1<<N);++j){dp[cur][j]=0;
for(int k=0;k<(1<<N);++k){
if(comp(j,k,N)) dp[cur][j]+=dp[cur^1][k];
}
}
cur^=1;
}
ans[N][M]=ans[M][N]=dp[cur^1][(1<<N)-1];
printf("%lld\n",dp[cur^1][(1<<N)-1]);
}
int main()
{
memset(ans,-1,sizeof(ans));
int N,M,i,j,k,l;
while(scanf("%d%d",&N,&M)!=EOF&&(N||M)){
if(N*M%2==1) {puts("0");continue;}
if(N>M) {swap(N,M);}
solve(N,M); //M行N列
}
return 0;
}
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
LL dp[2][2050];
LL ans[15][15];
bool check(int x,int i)
{ return x&(1<<i); }
bool comp(int A,int B,int N)
{
int i=0,j,k;
while(i<N){
if(!check(A,i)){
if(!check(B,i)) return 0;
i++;
}
else{
if(!check(B,i)) i++;
else {
if(i==N-1||!check(A,i+1)||!(check(A,i+1)&&check(B,i+1))) return 0;
else i+=2;
}
}
}
return 1;
}
void solve(int N,int M)
{
if(ans[N][M]+1) {printf("%lld\n",ans[N][M]);return;}
memset(dp,0,sizeof(dp));
dp[0][(1<<N)-1]=1;
int cur=1;
for(int i=1;i<=M;++i){
for(int j=0;j<(1<<N);++j){dp[cur][j]=0;
for(int k=0;k<(1<<N);++k){
if(comp(j,k,N)) dp[cur][j]+=dp[cur^1][k];
}
}
cur^=1;
}
ans[N][M]=ans[M][N]=dp[cur^1][(1<<N)-1];
printf("%lld\n",dp[cur^1][(1<<N)-1]);
}
int main()
{
memset(ans,-1,sizeof(ans));
int N,M,i,j,k,l;
while(scanf("%d%d",&N,&M)!=EOF&&(N||M)){
if(N*M%2==1) {puts("0");continue;}
if(N>M) {swap(N,M);}
solve(N,M); //M行N列
}
return 0;
}
POJ 2411 状压DP经典
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。