UVa 11270 铺放骨牌(轮廓线DP)

https://vjudge.net/problem/UVA-11270

题意:

用1×2骨牌覆盖n×m棋牌,有多少种方法?

 

思路:

这道题目是典型的轮廓线DP题。

所谓轮廓线DP,就是以整行整列为状态进行动态规划时无法进行状态转移,那么此时就可以用到轮廓线,当然,这种方法只能使用在一个窄棋盘上,大了肯定是不行的,要超时!

'

轮廓线DP就是按照从上到下,从左到右的顺序进行状态转移,每个格子用二进制来表示状态,1代表的就是覆盖,0代表未覆盖。

以本题为例,如上图,我们现在要计算 k 格子,那么与它有关的就是k4 k3 k2 k1 k0这5个格子。

 

现在,我们对于每个格子都有三种决策:

1、不放

     不放的条件是其上面的格子必须是1(也就是k4必须是1),否则无法覆盖所有的棋盘的。

     如果满足条件,那么就进行状态转移,d[cur][新状态]+=d[1-cur][旧状态],也就是d[cur][k3k2k1k0k]+=d[1-cur][k4k3k2k1k0]

2、上放

     上放的条件是其上面的格子必须是0。

3、左放

     左放的条件其左边的格子必须是0。

 

具体的算法实现请参见代码。

注意:这道题目数组开小点,开到1<<15会TLE,11就可以了!!

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<sstream>
 6 #include<vector>
 7 #include<stack>
 8 #include<queue>
 9 #include<cmath>
10 #include<map>
11 using namespace std;
12 typedef long long ll;
13 typedef pair<int,int> pll;
14 const int INF = 0x3f3f3f3f;
15 const int maxn=11;
16 
17 int n,m;
18 int cur;
19 ll d[2][1<<maxn];
20 
21 void update(int a,int b)   //a是m位的旧状态,b是m+1位的新状态
22 {
23     if(b&(1<<m))   d[cur][b^(1<<m)]+=d[1-cur][a];  //先检查新状态的轮廓线首是否为1,是1则更新状态
24 }                                                  //因为轮廓线首位1,所以b^(1<<m)就是将首位置为0,将新状态变成m位
25 
26 int main()
27 {
28     while(scanf("%d%d",&n,&m)==2)
29     {
30         if(n<m)   swap(n,m);
31         memset(d,0,sizeof(d));
32         d[0][(1<<m)-1]=1;
33         cur=0;
34         for(int i=0;i<n;i++)
35         {
36             for(int j=0;j<m;j++)
37             {
38                 cur^=1;
39                 memset(d[cur],0,sizeof(d[cur]));
40                 for(int k=0;k < (1<<m);k++)
41                 {
42                     update(k,k<<1);  //不放,直接将二进制左移一位形成新状态
43                     if(i && !(k&(1<<m-1)))  update(k,(k<<1)^(1<<m)^1);  //上放,要求轮廓线首为0且为非首行
44                     if(j && !(k&1))  update(k,(k<<1)^3);  //左放,要求轮廓线首为1,尾为0,且为非首列
45                 }
46             }
47         }
48         printf("%lld\n",d[cur][(1<<m)-1]);
49     }
50     return 0;
51 }

 

转载于:https://www.cnblogs.com/zyb993963526/p/7007061.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值