hdu 4804 Campus Design (2013 南京 轮廓线dp)

hdu 4804 Campus Design (2013 南京 )

水轮廓线dp,有一个类似的题目

Tiling Dominoes, Uva 11270, 轮廓线dp入门题

本题是在其基础上加了一些东西而已,

(1)可以放1*2的块、1*1的块,分别根据其特点转移即可

(2)

1*1的块有个数要求;增加一维表示用的1* 1块个数即可

(3)有些格子不能放,有些格子能放;分两种情况进行转移即可

dp[i][s][k]表示:i阶段s状态使用有k个1*1块时的覆盖方案总数(共n*m各阶段,每个阶段(1 <<m)- 1个状态)

 注意转移情况及转移时的条件

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
#include<map>
#include<set>
#define REP(i, n) for(int i=0; i<n; i++)
#define CLR(a, b) memset(a, b, sizeof(a))
#define PB push_back
#define LL long long
using namespace std;
const int MOD = 1e9 + 7;
int n, m;
int C, D;
int dp[2][1 << 10][22];
char ch[110][20];
int now, next;
int ALL;

void update(int nexts, int s, int nextk, int k)
{
    if (nexts & (1 << m))///转移时的条件,必须保证转移后,之前的格子,都被覆盖
    {
        dp[next][nexts ^ (1 << m)][nextk] += dp[now][s][k];
        if (dp[next][nexts ^ (1 << m)][nextk] >= MOD) dp[next][nexts ^ (1 << m)][nextk] %= MOD;
    }
}
int main()
{
    while (scanf("%d%d%d%d", &n, &m, &C, &D) != EOF)
    {
        REP(i, n) scanf("%s", ch[i]);
        CLR(dp, 0);
        now = 0;
        ALL = (1 << m) - 1;
        dp[0][ALL][0] = 1;

        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < m; j++)
            {
                next = now ^ 1;
                if (ch[i][j] == '0')/// 不可放时的转移
                {
                    for (int k = 0; k <= D; k++) for (int s = 0; s <= ALL; s++)
                        if (dp[now][s][k]) update((s << 1) ^ 1, s, k, k);
                }
                else///可以放时的转移
                {
                    for (int k = 0; k <= D; k++) for (int s = 0; s <= ALL; s++)
                        if (dp[now][s][k])
                        {
                            update((s << 1), s, k, k);///此处不放,直接转移
                            update((s << 1) ^ 1, s, k + 1, k);///放1*1块的转移
                            if (j && !(s & 1)) update((s << 1) ^ 3, s, k, k);///横着放1*2块时的转移
                            if (i && !(s & (1 << (m - 1)))) update((s << 1) ^ (1 << m) ^ 1, s, k, k);///竖着放1*2块是的转移
                        }
                }
                CLR(dp[now], 0);
                now ^= 1;
            }
        }
        int ans = 0;
        for (int i = C; i <= D; i++)
        {
            ans += dp[now][ALL][i];
            if (ans >= MOD) ans %= MOD;
        }
        printf("%d\n", ans);
    }
}




评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值