nyoj435 棋盘覆盖(二) (轮廓线dp)

本文详细探讨了棋盘覆盖问题的解决方案,通过使用轮廓线的方法处理不同形状的地砖(包括新增的L型砖),实现对特定尺寸的矩形区域进行完全覆盖。文中提供了一段C++代码示例,演示如何通过动态规划算法计算覆盖方案的数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

棋盘覆盖(二)

时间限制:1000 ms  |  内存限制:65535 KB
难度:4
描述
The banquet hall of Computer Scientists' Palace has a rectangular form of the size M x N (1<=M<=9, 1<=N<=9). It is necessary to lay hardwood floors in the hall. There are wood pieces of two forms:
1) rectangles (2x1) 
2) corners (squares 2x2 without one 1x1 square) 
You have to determine X - the number of ways to cover the banquet hall. 
Remarks. The number of pieces is large enough. It is not allowed to leave empty places, or to cover any part of a surface twice, or to saw pieces.
输入
The first line contains natural number M. The second line contains a natural number N. 

输出
First line should contain the number X, or 0 if there are no solutions.
样例输入
2 3
样例输出
5


铺地砖问题的变形,比原来多了个L型砖,依然用轮廓线去解决(没学过轮廓线的不建议看此博客,白书P383)

观察L砖,发现一共四种形式

(丑,轻喷)

对于第四种来说需要比原本的铺地砖问题的轮廓线还多一个位置,因此对于这题,轮廓线的长度为(m+1)

然后就按照轮廓线的步骤一步步地来

设轮廓线从末尾到开头的第i个位置为P[i]

对于要放的这点一共有7种放法

1:竖着放1*2的地砖,此时需要  P[m]=P[m-1]=1,P[0]=0;

2.横着放1*2的地砖,此时需要   P[m]=1,P[m-1]=0

3.什么也不放,此时需要  P[m]=1

4.放第一种L型砖  当前行不能为第一行,当前列不能为第一列且 P[m]=P[0]=0

5.放第二种L型砖  当前行不能为第一行,当前列不能为第一列且 P[m]=1,P[4]=P[0]=0

6.放第三种L型砖  当前行不能为第一行,当前列不能为最后一列且P[m]=1,P[m-1]=P[m-2]=0

7.放第四种L型砖  当前行不能为第一行,当前列不能为第一列且P[m]=P[m-1]=0

然后将新状态加上原本的方案数就行了

#include <cstdio>
#include <cstring>
#include <cctype>
#include <stdlib.h>
#include <string>
#include <map>
#include <iostream>
#include <sstream>
#include <cmath>
#include <algorithm>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
typedef long long ll;
const int N=11;
ll dp[2][1<<N];
int main()
{
    int n,m,cur;
    while(~scanf("%d%d",&n,&m))
    {
        if(n<m)swap(n,m);
        cur=0;
        dp[0][(1<<m+1)-1]=1;
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<m; j++)
            {
                cur^=1;
                mem(dp[cur],0);
                for(int k=0; k<1<<m+1; k++)
                {
                    if(j&&(k&(1<<m))&&!(k&1))//竖着放1*2的
                        dp[cur][((k^(1<<m))<<1)|3]+=dp[1-cur][k];
                    if(i&&(k&(1<<m))&&!(k&(1<<m-1)))//横着放1*2的
                        dp[cur][((k^(1<<m)|(1<<m-1))<<1)|1]+=dp[1-cur][k];
                    if(k&(1<<m))//不放
                        dp[cur][(k^(1<<m))<<1]+=dp[1-cur][k];
                    if(i&&j&&!(k&(1<<m))&&!(k&1))//第一种L型砖
                        dp[cur][k<<1|3]+=dp[1-cur][k];
                    if(i&&j&&(k&(1<<m))&&!(k&(1<<m-1))&&!(k&1))//第二种L型砖
                        dp[cur][(k^(1<<m)|(1<<m-1))<<1|3]+=dp[1-cur][k];
                    if(i&&(j!=m-1)&&(k&(1<<m))&&!(k&(1<<m-1))&&!(k&(1<<m-2)))//第三种L型砖
                        dp[cur][(k^(1<<m)|(3<<m-2))<<1|1]+=dp[1-cur][k];
                    if(i&&j&&!(k&(1<<m))&&!(k&(1<<m-1)))//第四种L型砖
                        dp[cur][(k<<1)|(1<<m)|1]+=dp[1-cur][k];
                }
            }
        }
        printf("%lld\n",dp[cur][(1<<m+1)-1]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值