题意:N 个木棒, 长度分别为1, 2, ..., N。构成美妙的栅栏。要求满足:除了两端的木棒外,每一跟木棒,要么比它左右的两根都长,要么比它左右的两根都短。即木棒呈现波浪状分布,这一根比上一根长了,那下一根就比这一根短,或反过来。符合上述条件的栅栏建法有很多种,对于满足条件的所有栅栏, 按照字典序(从左到右, 从低到高) 排序。问给定一个栅栏的排序号,请输出对应的栅栏方案, 即每一个木棒的长度。
思路(参考郭炜老师课件):用dp确定数量,输出采用排列计数的思想。
dp[i][k][DOWN]是i根木棒中以第k短的木棒打头的DOWN方案数。然后对C进行动归:dp[i][k][UP] = ∑ dp[i-1][M][DOWN],M = k ... i -1。dp[i][k][DOWN] = ∑ dp[i-1][N][UP],N = 1... k-1。
初始条件:dp[1][1][UP]=dp[1][1][DOWN] = 1。
接下来考虑计数问题:本题待求方案的序号为C
先假设第1短的木棒作为第一根,看此时的方案数 P(1)是否>=C,如果否,则应该用第二短的作为第一根,C减去P(1) ,再看此时方案数P(2)和C比如何。如果还 < C ,则应以第三短的作为第一根,C再减去P(2) ....若发现第i短的作为第一根时,方案数已经不小于C,则确定应该以第i短的作为第一根, C减去第i短的作为第一根的所有方案数,然后再去确定第二根。
下一根的长度与上一根的长度有关,可以用上一根取的是第几小来表示,而且当前是up方案还是down方案也与上一个方案种类相关。前者通过循环起始和终止位置控制,后者通过两个变量控制。具体见代码。
#include <cstdio>
#include <cstring>
#inclu