HDU4804 Campus Design (轮廓线DP)

骨牌变形题目,加入了一些限制元素,不仅可以填充1*2规格的骨牌还可以填充1*1大小的骨牌,对于1*1的骨牌,填充数量必须在[C,D]之间才合法,

且有部分格子有花,不能填充,求在满足所有条件的情况下将所有可填充的格子填满的不同方案个数,对1e9+7取模。

显然是个经典的题目了,我的bug就是少写了一个条件和一些思路上的不足,代码写的冗余了,哎。

一是记得最高位补零,由当前状态推放置后的状态时,左移后最高位已经不在轮廓线内切记归零。

二是缜密的逻辑,对所有的情况进行不重不漏的罗列。

我先根据当前位有没有花进行分类,有花的话只有最高位为1才可进行合法转移。

无花得话表示此位置可以进行放置,分为四种情况

一、不放置,当状态最高位为1时可进行合法转移。

二、放置1*1的砖块,当状态最高位为1时可进行合法转移。

三,竖直放置1*2砖块,当行数不为0且状态最高位为0时可进行合法转移。

四,水平放置1*2砖块,当列数不为零且状态最高位为1且最低位为零时可进行合法转移。

dp[i][j][k]含义:当前处理第i个轮廓线时,状态为j,j之前的所有可填充格子全部填满,目前消耗的1*1为k个的方案数。

呼~最后记得转移时注意1*1数量最大也就是D

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 int N,M,C,D;
 5 int e[105][25];
 6 LL mod=1e9+7;
 7 LL dp[2][1<<10][22];
 8 void update(int cur,int pre,int now,int f1,int f2)
 9 {
10     dp[cur][now][f2]=(dp[cur][now][f2]+dp[cur^1][pre][f1])%mod;
11 }
12 bool is1(int x,int y)
13 {
14     return x&(1<<y);
15 }
16 int to(int x,int y,int z)
17 {
18     if(z==1&&is1(x,y)) return x;
19     if(z==0&&(!is1(x,y))) return x;
20     if(z) return x|(1<<y);
21     if(!z) return x^(1<<y);
22 }
23 void solve()
24 {
25     memset(dp,0,sizeof(dp));
26     int i,j,k,cur=0;
27     dp[0][(1<<M)-1][0]=1;
28     for(i=0;i<N;++i){
29         for(j=0;j<M;++j){cur^=1;
30         memset(dp[cur],0,sizeof(dp[cur]));
31             for(k=0;k<(1<<M);++k){
32                if(!e[i][j]){
33                  if(is1(k,M-1)) {
34                     for(int t1=0;t1<=D;++t1)
35                         update(cur,k,to((k<<1)|1,M,0),t1,t1);
36                  }
37                }
38                else{
39                 if(is1(k,M-1)) for(int t1=0;t1<=D;++t1) update(cur,k,to((k<<1),M,0),t1,t1);
40                 if(is1(k,M-1)){   //1*1
41                     for(int t1=0;t1<D;++t1)
42                         update(cur,k,to((k<<1)|1,M,0),t1,t1+1);
43                 }
44                 if(i&&(!is1(k,M-1))){  //竖着放 1*2
45                     for(int t1=0;t1<=D;++t1)
46                         update(cur,k,to((k<<1)|1,M,0),t1,t1);
47                 }
48                 if(j&&(is1(k,M-1))&&(!is1(k,0))){
49                     for(int t1=0;t1<=D;++t1)
50                         update(cur,k,to((k<<1)^3,M,0),t1,t1);
51 
52                 }
53 
54                }
55             }
56         }
57     }LL ans=0;
58     for(int i=C;i<=D;++i) ans=(ans+dp[cur][(1<<M)-1][i])%mod;
59     cout<<ans<<endl;
60 }
61 int main()
62 {
63     int i,j; char c;
64     while(cin>>N>>M>>C>>D){
65         for(i=0;i<N;++i){
66             for(j=0;j<M;++j){cin>>c;
67             e[i][j]=c-'0';
68             }
69         }
70         solve();
71     }
72     return 0;
73 }

 

转载于:https://www.cnblogs.com/zzqc/p/7245443.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值