题意:给出一个n*m的矩形,然后用1*2大小的多米若骨牌去填充n*m的这个矩形,问有多少种填充方法。
分析:由于每个骨牌是1*2的矩形,之前的状压套路都不管用啦,然后去找博客是轮廓线,然后学习一下。
首先对于每个骨牌在(i,j)只能 横着连续两格(i, j+1)(i, j+1),与上一层(i-1, j) (i, j),或者与下一层(i,j)(i+1,j).三种放置方法。
然后状态转移方程是用dfs求出下一层的各种状态,然后转移。
代码:
#include<cstring>
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
long long dp[12][1<<11];
int n,m,t;
void dfs(int i,int s,int s1,int cut)//分别是当前位置,上一层状态,这一层当前状态,当前层数
{
if(i==m)
{
dp[cut+1][s1]+=dp[cut][s];
return ;
}
if(s&(1<<i)) //上一层为1,可以在这一层放置连续1,或者与下一层相连的骨牌
{
if(i<m-1&&(s&(1<<(i+1))))
dfs(i+2,s,s1<<2|3,cut);
dfs(i+1,s,s1<<1,cut);
}
else
{
dfs(i+1,s,s1<<1|1,cut);
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF&&(n||m))
{
if(n*m&1)//如果n*m为奇数,不可能刚好拼成
{
printf("0\n");
continue;
}
if(n<m)swap(n,m);//节省时间
memset(dp,0,sizeof(dp));
t=1<<m;
dp[0][t-1]=1;
for(int i=0;i<n;i++)
{
for(int j=0;j<t;j++)
{
if(dp[i][j]==0)continue;
dfs(0,j,0,i);
}
}
printf("%lld\n",dp[n][t-1]);
}
return 0;
}
题意:给你一个n*m的矩阵(1<=n<=100,1<=m<=10),矩阵里面分为空格和障碍物两种,现在用1*2,2*1,1*1的地板去铺满整个矩阵,且1*1地板所有个数的取值在[c,d]之间(1<=c<=d<=20),问你一共有多少种方法铺满?
解法和上一题十分类似。稍微麻烦一点。
#include<cstring>
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int MOD=1e9+7;
int n,m,dp[102][1<<10][21],c,d,a[105],t;
char ss[18];
void dfs(int i,int s,int l,int s1,int cut,int num)
{
if(i<0)
{
dp[cut+1][s1][l+num]=(dp[cut+1][s1][l+num]+dp[cut][s][l])%MOD;
return ;
}
if(s&(1<<i)||!(a[cut]&(1<<i)))
{
if((1<<i)&a[cut+1])
{
if(num+l<d)
{
dfs(i-1,s,l,s1<<1|1,cut,num+1);
}
if(i>0&&(s&(1<<(i-1))||!(a[cut]&(1<<(i-1))))&&a[cut+1]&(1<<(i-1)))
{
dfs(i-2,s,l,s1<<2|3,cut,num);
}
if((1<<i)&a[cut+2])
{
dfs(i-1,s,l,s1<<1,cut,num);
}
}
else
{
dfs(i-1,s,l,s1<<1,cut,num);
}
}
else
{
dfs(i-1,s,l,s1<<1|1,cut,num);
}
}
int main()
{
while(scanf("%d%d%d%d",&n,&m,&c,&d)!=EOF)
{
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
{
scanf(" %s",ss);
for(int j=0;j<m;j++)
{
if(ss[j]=='1')
a[i]|=(1<<(j));
}
//cout<<a[i]<<endl;
}
t=1<<m;
dp[0][t-1][0]=1;
for(int i=0;i<=n;i++)
{
for(int j=0;j<t;j++)
{
for(int l=0;l<=d;l++)
{
if(dp[i][j][l]==0)continue;
dfs(m-1,j,l,0,i,0);
}
}
}
int ans=0;
for(int i=c;i<=d;i++)
ans=(ans+dp[n][a[n]][i])%MOD;
printf("%d\n",ans);
}
return 0;
}