hdu4804Campus Design(轮廓线dp)

题目链接:点这里!!!


题意:给你一个n*m的矩阵(1<=n<=100,1<=m<=10),矩阵里面分为空格和障碍物两种,现在用1*2,2*1,1*1的地板去铺满整个矩阵,且1*1地板所有个数的取值在[c,d]之间(1<=c<=d<=20),问你一共有多少种方法铺满?


题解:

基础的轮廓线dp,分情况讨论清楚。

1、我们设dp[cur][g][k]为当前情况已用了g个1*1的板子枚举状态为k的方案数。

2、假设当前(i,j)是障碍物的话,说明我(i,j)这个点不用填东西,并且(i,j)是东西的。

3、假设当前(i,j)是空格的话,我们分情况考虑下:

(1)假设(i,j)我不填东西,说明(i-1,j)是有东西的。

(2)假设(i,j)我填1*1,说明(i-1,j)是有东西的。

(3)假设(i,j)我填(2*1),说明(i-1,j)是没有东西的。

(4)假设(i,j)我填(1*2),说明(i,j-1)是没有东西的,(i-1,j)是有东西的。

讨论完就ok啦!!!具体看代码!!


代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<vector>
#include<bitset>
#include<set>
#include<queue>
#include<stack>
#include<map>
#include<cstdlib>
#include<cmath>
#define pb push_back
#define pa pair<int,int>
#define clr(a,b) memset(a,b,sizeof(a))
#define lson lr<<1,l,mid
#define rson lr<<1|1,mid+1,r
#define bug(x) printf("%d++++++++++++++++++++%d\n",x,x)
#define key_value ch[ch[root][1]][0]
#pragma comment(linker, "/STACK:102400000000,102400000000")
typedef  long long LL;
const LL  MOD = 1000000007;
const int N = 55;
const int maxn = 1e6+15;
const int letter = 130;
const int INF = 1e9;
const double pi=acos(-1.0);
const double eps=1e-10;
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,m,c,d,cur,tt;
char s[110][15];
LL dp[2][25][1<<12];
///当前阶段放了k个1*1的方案为多少
void update(int a,int b,int p,int q){
    if(b&(1<<m)) dp[cur][p][b^(1<<m)]=(dp[cur][p][b^(1<<m)]+dp[1-cur][q][a])%MOD;
}
int main(){
    while(~scanf("%d%d%d%d",&n,&m,&c,&d)){
        clr(s,0);
        for(int i=0;i<n;i++) scanf("%s",s[i]);
        clr(dp,0);
        cur=0;
        dp[0][0][(1<<m)-1]=1ll;
        for(int i=0;i<n;i++)
        for(int j=0;j<m;j++){
            cur=cur^1;
            clr(dp[cur],0);
            if(s[i][j]=='1'){///empty
                for(int g=0;g<=d;g++){
                    for(int k=0;k<(1<<m);k++){
                        update(k,k<<1,g,g);
                        update(k,(k<<1)|1,g+1,g);
                        if(i&&!(k&(1<<m-1))) update(k,(k<<1)^(1<<m)^1,g,g);
                        if(j&&!(k&1)) update(k,(k<<1)^3,g,g);
                    }
                }
            }
            else {
                for(int g=0;g<=d;g++)
                    for(int k=0;k<(1<<m);k++)
                        update(k,(k<<1)|1,g,g);
            }
        }
        LL ans=0;
        for(int i=c;i<=d;i++) ans=(ans+dp[cur][i][(1<<m)-1])%MOD;
        printf("%I64d\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值