详解动态规划法

来源:互联网 发布:olga软件 编辑:程序博客网 时间:2024/06/05 00:49

看了刘汝佳的紫书:

一、从经典的三角形数问题开始。。

5357 9101281 62

(。。自我吐槽一下这个排版。。)

一个由非负整数组成的三角形,它的第一行有1个数,这个数的左下和右下各有一个数,以此类推...现在从第一行的数开始,每次往左下或者右下走一格,直到到达三角形底

部,要求所走的数字最后加起来最大。

考虑用二维数组储存数据,每个格子可以这样编号:

(1,1)

(2,1) (2,2)

(3,1) (3,2) (3,3)

(4,1) (4,2) (4,3) (4,4)

当前状态下如果要取得最大,必须保证下一个状态也是最大的,比如说在(i,j)这个位置,下一个状态可能是(i+1,j+1),或者(i+1,j),这样,如果用函数d(i,j)表示在(i,j)位取得的最大值,那么就有关系式:

d(i,j)=a(i,j)+max(d(i+1,j+1),d(i+1,j))

边界是当i=n的时候,第二项不存在,应该取0。

找到状态转移方程后可以:

1)递归求解

2)递推计算(逆向地)

3)记忆化搜索

使用memset(array,0,sizeof(array))或者memset(array,-1,sizeof(array)),表示初始时数组中的项都没有被计算过,然后再递归函数里加上控制条件保证每一项只被算一次,例如对于三角形问题:

memset(d,-1,sizeof(d));int solve(int i,int j){if(d[i][j]>=0)return d[i][j];return d[i][j]=a[i][j]+(i==n?0:max(solve(i+1,j+1),solve(i+1,j)));}

二、DAG上的动态规划

把问题归结为求DAG上的最长路或者最短路。

例如从i出发的最长路d(i)=max(d(j)+1|(i,j)∈E),其中(i,j)表示从i出发的边,E表示边集。


三、线性结构的动规

(1)最大上升子序列(LIS)问题

如果用d[i]来表示位置i处的LIS长度,那么d[i]就和它前面的所有位置都有关,这个关系是:d[i]等于它前面的位置里最大的LIS值加上1(如果i位置的数比前面位置大的话),也就是说:d[i]=max{d[j]|j<i,a[j]<a[i]}+1,其中a[]保存了这个序列。

最后的结果应该是d[]中的最大值。

下面这道题来自POJ(吐槽一下POJ长得好丑。。。还是浙大的PAT好哇:-))

POJ2533:

Longest Ordered Subsequence
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 54291 Accepted: 24288

Description

A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence (a1a2, ..., aN) be any sequence (ai1ai2, ..., aiK), where 1 <= i1 < i2 < ... < iK <= N. For example, sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, e. g., (1, 7), (3, 4, 8) and many others. All longest ordered subsequences are of length 4, e. g., (1, 3, 5, 8).

Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.

Input

The first line of input file contains the length of sequence N. The second line contains the elements of sequence - N integers in the range from 0 to 10000 each, separated by spaces. 1 <= N <= 1000

Output

Output file must contain a single integer - the length of the longest ordered subsequence of the given sequence.

Sample Input

71 7 3 5 9 4 8

Sample Output

4

Source

Northeastern Europe 2002, Far-Eastern Subregion

#include<stdio.h>#include<stdlib.h>int main(){int i,j,N;int* a;//store the inputint* d;//store the resultint max=0,dmax=1;scanf("%d",&N);a=(int*)malloc(sizeof(int)*(N+1));d=(int*)malloc(sizeof(int)*(N+1));for(i=1;i<=N;i++)scanf("%d",&a[i]);d[1]=1;//only a numberfor(i=2;i<=N;i++){max=0;//find the max of d[j] for(j=1;j<i;j++){if(d[j]>max&&a[j]<a[i]&&j<i)max=d[j];}d[i]=max+1;//find the max of d[i]if(d[i]>dmax)dmax=d[i];}printf("%d\n",dmax);return 0;}


运行效果截图:



(2)最长公共子序列(LCS)问题

POJ1458:

Common Subsequence
Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 54239 Accepted: 22542

Description

A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = < x1, x2, ..., xm > another sequence Z = < z1, z2, ..., zk > is a subsequence of X if there exists a strictly increasing sequence < i1, i2, ..., ik > of indices of X such that for all j = 1,2,...,k, xij = zj. For example, Z = < a, b, f, c > is a subsequence of X = < a, b, c, f, b, c > with index sequence < 1, 2, 4, 6 >. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y.

Input

The program input is from the std input. Each data set in the input contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct.

Output

For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.

Sample Input

abcfbc         abfcabprogramming    contest abcd           mnp

Sample Output

420

Source

Southeastern Europe 2003
#include<iostream>#include<string>#include<vector>using namespace std;int solve(string s1,string s2){int i,j,len1=s1.size(),len2=s2.size();vector<vector<int>> d(len1+1);for(i=0;i<=len1;i++){vector<int> tmp(len2+1,0);d[i]=tmp;}for(i=0;i<len1;i++)for(j=0;j<len2;j++){if(s1[i]==s2[j])d[i+1][j+1]=d[i][j]+1;elsed[i+1][j+1]=max(d[i+1][j],d[i][j+1]);}return d[len1][len2];}int main(){string s1,s2;while(cin>>s1>>s2){cout<<solve(s1,s2)<<endl;}return 0;}
。。。。不贴图了=。=

四、树的动规

待续

原创粉丝点击