动态规划03

2017-08-03  本文已影响0人  欣悦的灵魂

今天主要讨论如何解决高维的动态规划问题,即很难直接想出来递推关系。

美妙的栅栏

Richard just finished building his new house. Now the only thing the house misses is a cute little wooden fence. He had no idea how to make a wooden fence, so he decided to order one. Somehow he got his hands on the ACME Fence Catalogue 2002, the ultimate resource on cute little wooden fences. After reading its preface he already knew, what makes a little wooden fence cute. A wooden fence consists of N wooden planks, placed vertically in a row next to each other. A fence looks cute if and only if the following conditions are met:

此时,我们再尝试对B动规,找训B[i, k]和B[i - 1, j]之间的关系,但是第k短打头的时候,与i-1个木棍的所有排列可能又要分情况讨论,即:

     B[i, k] = sum(B[i - 1, j]) j = k, k + 1,..., i - 1 #后面的B都满足先降后升,即我们要把一个第k短的木板放到开头,使第二根比他高
     B[i, k] = sum(B[i - 1, j]) j = 1, 2, 3 ... , k - 1 #后面的B都满足先升后降,即我们要把一个第k短的木板放到开头,使第二根比他矮

于是,我们设C[i, k ,DOWN]表示第k短开头,并且满足先降后升的性质,C[i, k ,UP]表示第k短开头,并且满足先升后降的性质。这样,我们的递推关系就找到了:

 C[i, k, DOWN] = sum(C[i - 1, j, UP]) j = k, k + 1, ... , i-1
 C[i, k, UP]   = sum(C[i - 1, j, UP]) j = 1, 2, 3 ... , k-1
void solve(){
    int i,j,k;
    memset(dp, 0, sizeof(dp));
    dp[1][1][0] = dp[1][1][1] = 1;
    for(i = 2;i<=n;i++){
        for(j = 1;j<=i;j++){
            for(k = 1;k<=j-1;k++)
                dp[i][j][1] += dp[i-1][k][0];
            for(k = j;k<=i-1;k++)
                dp[i][j][0] += dp[i-1][k][1];
        }
    }
}

我们找到数目的递推关系之后,还要能找出任意某个排列的具体情况,即用到排序计数的思想:

举一个例子说明:假使我们有4根木棍,我们要求第三种排列
  * 1打头的总数B[4, 1] = 1,2打头的总数为B[4, 2] = 3,那我们就知道第二种排列就在2打头的里面,并且是第二个。第一个数字确定为2.
  * 2打头里面,先考虑DOWN的情况(因为DOWN的情况字典序一定小)C[4, 2, DOWN] = 1,C[4, 2, UP] = 2,于是总体的第三个就是C[4, 2, UP] 中第一个,即第二个数字确定为3.
  * 23打头里面DOWN的第一个为1,即第三个数字确定为1
  * 231打头里面第一个UP的数字为4,即第四个数字确定为4,所以结果就是2314。

代码很难写,还没写出来。。

作业题

上一篇 下一篇

猜你喜欢

热点阅读