POJ2411 轮廓线动态规划典型例题

Poj2411 Mondriaan's Dream

给出一个n*m的矩形,然后用1*2大小的多米若骨牌去填充n*m的这个矩形,问有多少种填充方法。

分析:典型的轮廓线动态规划题目。详见刘汝佳新书:算法竞赛入门经典:训练指南P384.

首先本题目是以一个一个的格子为基础来计算状态的,即每次都是考虑当前位置的格子如何放左上骨牌(以当前位置为最右下角,即只不放,左放,和上放3种情况,没有右放和下放)。且本题的状态都是一条一条的轮廓线。如图:

1

1

1

1

1

1

1

K4

K3

K2

K1

K0

O

 

 

 

 

 

 

 

为这5个数字对应的二进制值的十进制结果。K3K2K1K0O=11110表示由这5个格构成的轮廓线状态 如

K4 K3 K2 K1 K0 O 分别为: 0 1 1 1 1 0 时,

= 30, = 15

本题的状态为d[cur][]表示 当前以O格为末尾的轮廓线状态为的值对应二进制表示时且K3之前的所有格子的值都为1时构成上图所给状态的方法总数。其中 当前轮廓线为K3K2K1K0O,前一个轮廓线为K4K3K2K1K0。当前的轮廓线状态数用d[cur][ ]表示,前一个轮廓线状态数用d[1-cur][ ]表示。

现在初始时 K4K3K2K1K0O的值对应为 011110.

O格的每一种操作(不放,左方,上方)都会联系前后两种不同的轮廓线。

假设在O格放上骨牌,K4和O值都变为1,则d[cur][] =d[cur][<11111>]  +=d[1-cur][]=d[1-cur][<01111>] 这句话的意义是 在O格放上骨牌,则以O格为末尾的轮廓线为11111,且已放的格子情况为:

1

1

1

1

1

1

1

1

1

1

1

1

1

 

 

 

 

 

 

 

 

 

 

 

 

的时候有d[1-cur][<01111>](这是一个整数值)这么多种情况是通过在轮廓线=<01111>的基础上,放O格上骨牌而产生来的。

假设在O格不放,K4的值不改变依然为0,如果执行:d[cur][] =d[cur][<11110>]  +=                            d[1-cur][]=d[1-cur][<01111>] 这样是非法的。因为不放O格,K4的值永远为0(K4的值如果为0只能通过O格放上骨牌来置1,O格之后的格子无论怎么放骨牌都不会改变K4的值),所以如果执行上述非法操作,违反了关于d[cur][]的定义(要求K3之前所有格子的值都为1).

 

假设在O格放左骨牌,也是非法操作,因为O格左边已经是1了,不可能放的下左骨牌。

且在首行不能上放,在首列不能左放。

 

最后当循环处理到第(n,m)格时,轮廓线为<11111>时表示轮廓线前面的n-1行也全是11111,所以最终结果为d[cur][<11111>]。

并且初始值为d[0][<11111>]=1,其他d[0][其他值]=0(其实这个可以不弄,因为首行不能上放,所以首行轮廓线状态数不可能会引用到d[0][01111]这样的初值。)。

 

AC代码:

#include
#include
#include
using namespace std;
const int maxn = 15;
long long d[2][1<n)swap(n,m);
        memset(d,0,sizeof(d));
        cur=0;
        d[cur][(1<

 

你可能感兴趣的:(ACM--轮廓线动态规划,★★★,ACM--题解汇总)