Getting dp (first put in here, after carefully reading)

Reprinted URL link: http://bbs.chinaunix.net/thread-4094539-1-1.html

Dynamic programming: from novice to expert

Hawstein translation


Foreword

The problems we encountered, there can be a large part of dynamic programming (referred to as DP) to solve. To solve such problems can greatly enhance your ability and skills, I'll try to help you understand how to use the DP to solve problems. This article is based on an example in terms of expansion, because it is difficult to understand dry theory.

Note: If you already know for which a section and do not want to read it, it does not matter, you can skip it.

Introduction (introductory)

What is dynamic programming, how do we describe it?

Usually based on dynamic programming algorithm is a recursive formula and one or more initial state. A problem child by child on the solution of the problem of the introduction of the current solution. To solve problems using dynamic programming needs only polynomial time complexity, so it is much faster than backtracking, violent method.

Let's look at an example to understand the basic principles of DP.

First of all, we need to find the optimal solution of a state, then under it with the help of a state of optimal solution found.

What "state" stands for and how to find it?

"Status" is used to describe the problem of sub-problem solutions. There are two original authors explained was not clear, skip directly to the examples.

If we have a face value of 1, $ 3 and $ 5 coins several pieces, how to use the least coin lobbied for 11 yuan? (This question can be used on the surface of the greedy algorithm, but can not guarantee the greedy algorithm can be obtained solution, such as 1 yuan 2 yuan into time)

First, we think about a problem, how i lobbied yuan (i <11) with the least coin? Why do you ask it? Two reasons: 1. When we encounter a big problem, always accustomed to the scale of the problem is small, it is easy to analysis and discussion. 2. The smaller the size of the problem and the original problem is homogeneous, in addition to smaller scale, other are the same, in essence it is the same issue (issue after the child is actually smaller scale the original problem problem).

Well, let's start from the smallest i it. When i = 0, that is, how many coins we need to be lobbied 0. Since 1,3,5 greater than 0, that is no small denominations than 0, so we lobbied 0 yuan minimum of 0 coins. (This analysis is not silly? Do not worry, this idea will help us to sort out exactly what to do dynamic programming.) This time we find a mark to indicate with the phrase "We lobbied 0 yuan minimum of 0 coins. "I would be more convenient if the text has been used to express, not for a while you will feel around. Then, we use the d (i) = j i got enough to represent a minimum of the j-th element of the coin. So we've got d (0) = 0, represents the minimum required lobbied 0 0 yuan coins. When i = 1, only the face value of 1 yuan coins available, so we picked up a coin denominations of 1, then only lobbied 0 yuan can be, and this is already know the answer, that d (0) = 0. Therefore, d (1) = d (1-1) + 1 = d (0) + 1 = 0 + 1 = 1. When i = 2, is still only available in denominations of 1 coin, so I picked up a coin denominations of 1, then I just have lobbied 2-1 = 1 yuan to (remember to use the smallest number of coins ), and this already know the answer. Therefore, d (2) = d (2-1) + 1 = d (1) + 1 = 1 + 1 = 2. Up to this point, you may feel bored, I feel like the students of the subject do like. Because we have been operating only for the face value of the coin 1! Be patient, let us look at the case of i = 3 in. When i = 3, we can use the coin there are two: the $ 1 and $ 3 ($ 5 still useless, because the number you need to take care of 3 yuan five yuan is too much pro!). Since the use of the coin, there are two, I have two options. If I took a $ 1 coin, my goal becomes the: round up 3-1 = 2 yuan minimum number of coins needed. I.e., d (3) = d (3-1) + 1 = d (2) + 1 = 2 + 1 = 3. This program say is that I get three $ 1 coins; I picked up the second program is a three-dollar coin, my goal becomes: 3-3 lobbied = 0 yuan minimum number of coins needed. I.e., d (3) = d (3-3) + 1 = d (0) + 1 = 0 + 1 = 1. This program say is that I get a $ 3 coins. Well, these two programs which better it? But remember that we use the minimum number of coins to round up $ 3. So, choose d (3) = 1, how come? DETAILED is obtained: d (3) = min {d (3-1) +1, d (3-3) +1}.

OK, so many code words say specific things that make us a little abstract. From the above text, we have to extract a very important dynamic programming in two concepts: states and state transition equation.

Above d (i) represents the i lobbied for the minimum number of coins needed yuan, we define it as "state" for the problem, the state is how to find out? I (a) written in the knapsack problem dynamic programming of another article: According to the definition of sub-state problem. You find sub-problems, the state also surfaced. We demand the ultimate solution of the problem, you can use this status to represent: d (11), that is, how many coins lobbied for a minimum of 11 yuan. What state transition equation is it? Since we state represented by d (i), then the state transition equation of the natural inclusive d (i), comprises the above state equation d (i) is: d (3) = min {d (3-1) +1, d (3-3) +1}. Yes, it is the state transition between the equations that describe how the state is transferred. Of course, we have to look at it abstract,

d (i) = min {d (i-vj) +1}, where i-vj> = 0, vj represents the j-th denomination coins;

With the state and the state transition equation, the problem will be solved basically. Of course, Talk is cheap, show me the code!

Pseudo-code as follows:

FIG case when i is from 0 to 11 Solutions:

Can be derived from the FIG., 11 yuan together enough to at least three coins.

In addition, by tracking how we are worthy of the previous state to the current state value, can be found every time we use is what denominations of coins. For example, from the above FIG we can see the final result d (11) = d (10) +1 (face value of 1), and d (10) = d (5) +1 (nominal value of 5), and finally d (5) = d (0) +1 (nominal value of 5). So we lobbied for three coins requires a minimum of 11 yuan is: $ 1, $ 5, $ 5.

Note: The original text would have had some here, but I'm back and forth to repeat several times, probably means I have analyzed above from i = 0 to i = 3 in the reflected. Popular author had wanted to talk about some of the results did not write, but more difficult to understand, so this does not translate.

primary

We discussed above, a very simple example. Now let's look for more complex problems, how to find a way to transfer between states (that is, to find the state transition equation). We have had to introduce a new word called recurrence relations to the state of the link (or say state transition equation)

OK, the example of how it works.

It has a sequence number N: A [1], A [2], ..., A [N], to obtain the longest sequence length nondecreasing. (A problem speaking basic DP will be mentioned LIS: longest increasing subsequence)

As above, we are talking about the face of such a problem, we must first define a "state" to represent its sub-problems, and its solution is found. Note that in most cases, only one state and a state that appears in front of it, independent of the back of the state.

Let us follow the "Getting Started" section in the idea that the road to a simple question step by step to find the "state" and "state transition equation." If we consider the demand A [1], A [2 ], ..., A longest nondecreasing sequence length, where i <N, then the above problem becomes a subproblem of the original problem (problem of small-scale , you can let i = 1,2,3, etc. analysis) then we define D (i), i represents the number of the former a to the length of the longest non-reducing end of the sequence. OK, control the "Getting Started" in the simple questions, you should be able to estimate the d (i) we are looking for the state. If we put d (1) to d (N) are calculated, so we are looking for the ultimate answer is that there is the greatest. The state found, the next step to find out the state transition equation.

To facilitate understanding of how we find the state transition equation, I put the following example mentioned earlier terms. If this sequence number N we ask is:

5,3,4,8,6,7

The state found above, we can obtain the longest :( nondecreasing sequence below are represented by LIS)

  • Before a number of LIS length d (1) = 1 (sequence: 5)

  • 2 before the number of LIS length d (2) = 1 (sequence: 3; 3 in front of not less than 3)

  • 3 before the number of LIS length d (3) = 2 (sequence: 3,4; 4 in front of a smaller than its 3, the d (3) = d (2) +1)

  • 4 before the number of LIS length d (4) = 3 (sequence: 3,4,8; 8 are in front of it is smaller than the number 3, the d (4) = max {d (1), d (2) , d (3)} + 1 = 3)

OK, to analyze it, I think the state transition equation is already evident, if we have calculated the d (1) to d (i-1), then d (i) can be obtained by the state transition equation below:

d(i) = max{1, d(j)+1},其中j<i,A[j]<=A

Vernacular is explained, would like to request D (i), i put the respective sequences the foregoing, the last number is not greater than A sequence length plus 1, and then remove the maximum length is the d (i). Of course, it is possible i foregoing respective sequence number greater than the last A , then d (i) = 1, i.e., it becomes itself a subsequence of length 1.

Analysis finished, the second column of FIG :( i represents the length of the number in front of the LIS, the third column represents, LIS reached in a number of the index number of the current, can be obtained according to this sequence LIS)

Talk is cheap, show me the code:

#include <iostream>usingnamespacestd;intlis(intA[],intn){int*d=newint[n];intlen=1;for(inti=0;i<n;++i){d=1;for(intj=0;j<i;++j)if(A[j]<=A&&d[j]+1>d)d=d[j]+1;if(d>len)len=d;}delete[]d;returnlen;}intmain(){intA[]={5,3,4,8,6,7};cout<<lis(A,6)<<endl;return0;}

The time complexity of the algorithm is O (n2), is not the optimal solution. There is also a very clever algorithm time complexity can be reduced to O (nlogn), the Internet has introduced various articles it, not repeat them here. Portal: LIS of O (nlogn) solution. This problem can also use the "Sort + LCS" to solve, self-interested, Google.

Exercises

无向图G有N个结点(1<N<=1000)及一些边,每一条边上带有正的权重值。 找到结点1到结点N的最短路径,或者输出不存在这样的路径。

提示:在每一步中,对于那些没有计算过的结点, 及那些已经计算出从结点1到它的最短路径的结点,如果它们间有边, 则计算从结点1到未计算结点的最短路径。

尝试解决以下来自topcoder竞赛的问题:

  • ZigZag – 2003 TCCC Semifinals 3

  • BadNeighbors – 2004 TCCC Round 4

  • FlowerGarden – 2004 TCCC Round 1

中级

接下来,让我们来看看如何解决二维的DP问题。

平面上有N*M个格子,每个格子中放着一定数量的苹果。你从左上角的格子开始, 每一步只能向下走或是向右走,每次走到一个格子上就把格子里的苹果收集起来, 这样下去,你最多能收集到多少个苹果。

解这个问题与解其它的DP问题几乎没有什么两样。第一步找到问题的“状态”, 第二步找到“状态转移方程”,然后基本上问题就解决了。

首先,我们要找到这个问题中的“状态”是什么?我们必须注意到的一点是, 到达一个格子的方式最多只有两种:从左边来的(除了第一列)和从上边来的(除了第一行)。 因此为了求出到达当前格子后最多能收集到多少个苹果, 我们就要先去考察那些能到达当前这个格子的格子,到达它们最多能收集到多少个苹果。 (是不是有点绕,但这句话的本质其实是DP的关键:欲求问题的解,先要去求子问题的解)

经过上面的分析,很容易可以得出问题的状态和状态转移方程。 状态S[j]表示我们走到(i, j)这个格子时,最多能收集到多少个苹果。那么, 状态转移方程如下:

S[j]=A[j] + max(S[i-1][j], if i>0 ; S[j-1], if j>0)

其中i代表行,j代表列,下标均从0开始;A[j]代表格子(i, j)处的苹果数量。

S[j]有两种计算方式:1.对于每一行,从左向右计算,然后从上到下逐行处理;2. 对于每一列,从上到下计算,然后从左向右逐列处理。 这样做的目的是为了在计算S[j]时,S[i-1][j]和S[j-1]都已经计算出来了。

伪代码如下:

以下两道题来自topcoder,练习用的。

  • AvoidRoads – 2003 TCO Semifinals 4

  • ChessMetric – 2003 TCCC Round 4


中高级

这一节要讨论的是带有额外条件的DP问题。

以下的这个问题是个很好的例子。

无向图G有N个结点,它的边上带有正的权重值。

你从结点1开始走,并且一开始的时候你身上带有M元钱。如果你经过结点i, 那么你就要花掉S元(可以把这想象为收过路费)。如果你没有足够的钱, 就不能从那个结点经过。在这样的限制条件下,找到从结点1到结点N的最短路径。 或者输出该路径不存在。如果存在多条最短路径,那么输出花钱数量最少的那条。 限制:1<N<=100 ; 0<=M<=100 ; 对于每个i,0<=S<=100;正如我们所看到的, 如果没有额外的限制条件(在结点处要收费,费用不足还不给过),那么, 这个问题就和经典的迪杰斯特拉问题一样了(找到两结点间的最短路径)。 在经典的迪杰斯特拉问题中, 我们使用一个一维数组来保存从开始结点到每个结点的最短路径的长度, 即M表示从开始结点到结点i的最短路径的长度。然而在这个问题中, 我们还要保存我们身上剩余多少钱这个信息。因此,很自然的, 我们将一维数组扩展为二维数组。M[j]表示从开始结点到结点i的最短路径长度, 且剩余j元。通过这种方式,我们将这个问题规约到原始的路径寻找问题。 在每一步中,对于已经找到的最短路径,我们找到它所能到达的下一个未标记状态(i,j), 将它标记为已访问(之后不再访问这个结点),并且在能到达这个结点的各个最短路径中, 找到加上当前边权重值后最小值对应的路径,即为该结点的最短路径。 (写起来真是绕,建议画个图就会明了很多)。不断重复上面的步骤, 直到所有的结点都访问到为止(这里的访问并不是要求我们要经过它, 比如有个结点收费很高,你没有足够的钱去经过它,但你已经访问过它) 最后Min[N-1][j]中的最小值即是问题的答案(如果有多个最小值, 即有多条最短路径,那么选择j最大的那条路径,即,使你剩余钱数最多的最短路径)。

伪代码:

下面有几道topcoder上的题以供练习:

  • Jewelry – 2003 TCO Online Round 4

  • StripePainter – SRM 150 Div 1

  • QuickSums – SRM 197 Div 2

  • ShortPalindromes – SRM 165 Div 2


高级

以下问题需要仔细的揣摩才能将其规约为可用DP解的问题。

问题:StarAdventure – SRM 208 Div 1:

给定一个M行N列的矩阵(M*N个格子),每个格子中放着一定数量的苹果。 你从左上角的格子开始,只能向下或向右走,目的地是右下角的格子。 你每走过一个格子,就把格子上的苹果都收集起来。然后你从右下角走回左上角的格子, 每次只能向左或是向上走,同样的,走过一个格子就把里面的苹果都收集起来。 最后,你再一次从左上角走到右下角,每过一个格子同样要收集起里面的苹果 (如果格子里的苹果数为0,就不用收集)。求你最多能收集到多少苹果。

注意:当你经过一个格子时,你要一次性把格子里的苹果都拿走。

限制条件:1 < N, M <= 50;每个格子里的苹果数量是0到1000(包含0和1000)。

如果我们只需要从左上角的格子走到右下角的格子一次,并且收集最大数量的苹果, 那么问题就退化为“中级”一节里的那个问题。将这里的问题规约为“中级”里的简单题, 这样一来会比较好解。让我们来分析一下这个问题,要如何规约或是修改才能用上DP。 首先,对于第二次从右下角走到左上角得出的这条路径, 我们可以将它视为从左上角走到右下角得出的路径,没有任何的差别。 (即从B走到A的最优路径和从A走到B的最优路径是一样的)通过这种方式, 我们得到了三条从顶走到底的路径。对于这一点的理解可以稍微减小问题的难度。 于是,我们可以将这3条路径记为左,中,右路径。对于两条相交路径(如下图):

在不影响结果的情况下,我们可以将它们视为两条不相交的路径:

这样一来,我们将得到左,中,右3条路径。此外,如果我们要得到最优解, 路径之间不能相交(除了左上角和右下角必然会相交的格子)。因此对于每一行y( 除了第一行和最后一行),三条路径对应的x坐标要满足:x1[y] < x2[y] < x3[y]。 经过这一步的分析,问题的DP解法就进一步地清晰了。让我们考虑行y, 对于每一个x1[y-1],x2[y-1]和x3[y-1],我们已经找到了能收集到最多苹果数量的路径。 根据它们,我们能求出行y的最优解。现在我们要做的就是找到从一行移动到下一行的方式。 令Max[j][k]表示到第y-1行为止收集到苹果的最大数量, 其中3条路径分别止于第i,j,k列。对于下一行y,对每个Max[j][k] 都加上格子(y,i),(y,j)和(y,k)内的苹果数量。因此,每一步我们都向下移动。 我们做了这一步移动之后,还要考虑到,一条路径是有可能向右移动的。 (对于每一个格子,我们有可能是从它上面向下移动到它, 也可能是从它左边向右移动到它)。为了保证3条路径互不相交, 我们首先要考虑左边的路径向右移动的情况,然后是中间,最后是右边的路径。 为了更好的理解,让我们来考虑左边的路径向右移动的情况,对于每一个可能的j,k对(j<k), 对每个i(i<j),考虑从位置(i-1,j,k)移动到位置(i,j,k)。处理完左边的路径, 再处理中间的路径,最后处理右边的路径。方法都差不多。

用于练习的topcoder题目:

  • MiniPaint – SRM 178 Div 1


其它

当阅读一个题目并且开始尝试解决它时,首先看一下它的限制。 如果要求在多项式时间内解决,那么该问题就很可能要用DP来解。遇到这种情况, 最重要的就是找到问题的“状态”和“状态转移方程”。(状态不是随便定义的, 一般定义完状态,你要找到当前状态是如何从前面的状态得到的, 即找到状态转移方程)如果看起来是个DP问题,但你却无法定义出状态, 那么试着将问题规约到一个已知的DP问题(正如“高级”一节中的例子一样)。

转载于:https://www.cnblogs.com/cstdio1/p/11054951.html

Guess you like

Origin blog.csdn.net/weixin_34080903/article/details/93162770