1、st中存的是每一行摆放的所有可能,0是空着,1是占着,st[i][0]中存一行的可能的状态即from,st[i][1]中存与其匹配的下一行状态即to;
2、dfs中from是一行中前n个格子的状态,to是与之吻合的状态;
3、因为只看每一行的可能状态,所以dfs中的n==w时已取完该种可能,退出递归;
4、对于一行的第n列,采取三种摆放长方形的方式
dfs(n+2,(from<<2)+3,(to<<2)+3); //横着放,这层和下一层匹配的都多两位1 (二进制11就是3嘛)
dfs(n+1,(from<<1)+1,to<<1);//竖着放,这层多一个1,匹配下层这个位置是0
dfs(n+1,from<<1,(to<<1)+1);//不放,这层多一个0,匹配的下层多个1
5、dp[i][j]中存第i行摆放状态为j时的方法数,边界是要全放满的,dp[0][(1<<w)-1]=1,最后要求的是dp[h][(1<<w)-1];
6、dp过程是
for(i=1;i<=h;i++)
{
for(j=0;j<cnt;j++)
{
dp[i][st[j][1]]+=dp[i-1][st[j][0]];
}
}
#include<stdio.h>
#include<string.h>
int st[3000][2];
int dp[11][3000]; //2^11=2048最多的状态数
int cnt,h,w;
void dfs(int n,int from,int to)//枚举所有一行摆放的可能和其匹配的下层
{
if(n>w)
return;
if(n==w) //这一行刚好摆完,得到一行摆放的组合
{
st[cnt][0]=from;
st[cnt][1]=to;
cnt++;
return;
}
dfs(n+2,(from<<2)+3,(to<<2)+3); //横着放,这层和下一层匹配的都多两位1
dfs(n+1,(from<<1)+1,to<<1);//竖着放,这层多一个1,匹配下层这个位置是0
dfs(n+1,from<<1,(to<<1)+1);//不放,这层多一个0,匹配的下层多个1
}
int main()
{
int i,j;
while(scanf("%d %d",&h,&w)&&h)
{
if((w*h)%2)
{
printf("0\n");
continue;
}
memset(dp,0,sizeof(dp));
memset(st,0,sizeof(st));
cnt=0; //记录每一行摆放所有可能的状态总数
dfs(0,0,0);
dp[0][(1<<w)-1]=1;//边界
for(i=1;i<=h;i++)
{
for(j=0;j<cnt;j++)
{
dp[i][st[j][1]]+=dp[i-1][st[j][0]];
}
}
printf("%d\n",dp[h][(1<<w)-1]);
}
return 0;
}
本文介绍了一种通过深度优先搜索(DFS)与动态规划(DP)相结合的算法来解决矩形填充问题。该算法用于计算在给定高度h和宽度w的矩阵中,如何用1x2的矩形砖块填满整个矩阵的不同方法的数量。文中详细解释了DFS和DP的实现步骤,包括状态转移方程和边界条件。
965

被折叠的 条评论
为什么被折叠?



