zoj2136 经典动态规划 求最长上升子序列
2009-07-10 20:09
239 查看
Longest Ordered Subsequence
题意:求一个数列的最长上升子序列。
输入:包括多组数据。每个数据包括两行,第一行整数N(1 <= N <= 1000)表示数列长度。第二行是N个0--10000之间的整数。
输出:每个数据输出一个整数,表示最长上升子序列的长度。
注意输入每组数据之间有空行。输出也一样。
Sample Input
1
7
1 7 3 5 9 4 8
Sample Output
4
题解:最简单的O(n^2)的算法是f[i]=max{f[j]+1} ( j<i , a[j]<a[i] )
代码如下
下面我们来看O(nlogn)的算法。
我看到一个很好理解的文章:http://blog.sina.com.cn/s/blog_575e6b9d010007cp.html
代码正在实现中。。待续
题意:求一个数列的最长上升子序列。
输入:包括多组数据。每个数据包括两行,第一行整数N(1 <= N <= 1000)表示数列长度。第二行是N个0--10000之间的整数。
输出:每个数据输出一个整数,表示最长上升子序列的长度。
注意输入每组数据之间有空行。输出也一样。
Sample Input
1
7
1 7 3 5 9 4 8
Sample Output
4
题解:最简单的O(n^2)的算法是f[i]=max{f[j]+1} ( j<i , a[j]<a[i] )
代码如下
program z2136; var t,n,i:integer; a,f:array[1..1001] of integer; procedure init; var i:integer; begin readln(n); for i:=1 to n do begin read(a[i]); f[i]:=1; end; end; procedure dp; var i,j,maxx:integer; begin for i:=2 to n do begin maxx:=-maxint; for j:=1 to i-1 do if (f[j]+1>maxx)and(a[j]<a[i]) then maxx:=f[j]+1; if maxx<>-maxint then f[i]:=maxx; end; end; procedure print; var i,maxL:integer; begin maxL:=-maxint; for i:=1 to n do if maxL<f[i] then maxL:=f[i]; writeln(maxL); end; begin readln(t); readln; for i:=1 to t do begin init; dp; print; if i<>t then begin writeln; readln end; end; end.
下面我们来看O(nlogn)的算法。
我看到一个很好理解的文章:http://blog.sina.com.cn/s/blog_575e6b9d010007cp.html
【解题思路】 一道典型的DP(动态规划)题。可以从两个方向着手,即:从左往右和从右往左。由于从右往左比较符合一般思想,故采用后者做算法示例。 首先我们设定一个flag[]来保存每种长度的上升串中的第一个元素值。比如上升串是2 5 8,那么在flag[3]这个位置应该存储2,即flag[i]表示i长度的上升串的首元素(该元素在上升串中值最小,且如果要增长这个串必须满足:新加入元素<flag[i]) 对于一个原始串:1 7 3 5 9 4 8 来说,我们可以从右往左看(<-)。 1)首先遍历8,由于自身就是个上升串,故flag[1]=8。 2)其次映入眼帘的是4,这是4小于flag[1]=8,可以组成更长的上升串,故flag[2]=4,但此时我们不能取消掉flag[1]中的值8,比如在下列串中:5 6 7 4 8,后进入的7,明显可以组成比4-8更有“潜力”继续增长的,事实也证明,5 6 7 8比4 8更“长”,所以flag[1]=8我们将继续保留以备不时之需。 3)接下来读入的是9,它比任何一个flag[i]都大,其实我们不难发现flag[1]>flag[2]>flag[3]……flag ,公理上我就不证明了,因为flag[i+1]总是在flag[i]的基础上添加一个比flag[i]小的数得到的,所以上面的公式十分自然,因此我们只要比较出9>flag[1],就不必再比较后面了。这时,我们只需更新flag[1]=8为flag[i]=9,因为9比8更具备增长的潜力,比如前面还有个8,这是8-9就比8长(因为不能有8-8)。 4)再下来是5,我们发现flag[1]=9>5>flag[2]=4,在这种情况下,5-9相比4-8来说更具备增长潜力(因为5>4),所以flag[2]=4被更新为flag[2]=5。 5)碰到3的时候,因为3小于任何一个flag[i](除去初始化为0的那些flag[i]),扫描到flag[2]=5>3,且flag[3]=0时,我们将flag[3]赋值为3,这步与2)加入4的操作类似。 …………………… 最后就得出了一个flag数组,其中flag[1]=9,flag[2]=7,flag[3]=3,flag[4]=1(其余flag[5]……flag 都=0,因为初始化为0)。其实,我们可以设置个max变量,在每次上升串增长的时候,比较新上升串是否>max,如果成立,则max=新增长的上升串的长度。 由此我们可以得出该从右向左扫描算法的一般表达式: i)如果max=0(初始状态,表示扫描右边第一个元素),则flag[1]=in(in表示此时正扫描到的元素),max++; ii)如果in>flag[1];则flag[i]=in; iii)如果flag[i]>in>flag[i+1],且max不等于1时(也就是大于1),分两种情况:(1)flag[i+1]不为0时,即前面的例子中的第四步,flag[i+1]=in;(2)flag[i+1]=0时,也就是新扫描到的in小于每一个已经扫描过的元素,则flag[i+1]=in的同时,max还应该加1,也就是上例中的第二步和第五步。 最后还是要重申一点,如果在循环判断的过程中,出现flag[i]=in的情况下,直接放弃这次操作,不加处理。否则像1 2 2 3 3 4 4 这样的输出结果会成为7,而不是正确结果4。
代码正在实现中。。待续
相关文章推荐
- 动态规划——最长上升子序列
- sdut1299 最长上升子序列(动态规划)
- zoj 2432(最长递增上升子序列)
- 动态规划——求最长下降/上升子序列
- 动态规划——求最长下降/上升子序列
- 【动态规划】最长上升子序列(LIS)
- HDU 3998 Sequence(经典问题,最长上升子序列)
- 动态规划-最长上升子序列LIS
- zoj 2391 Beautiful People 最长上升子序列
- ZOJ 2319 最长上升子序列并输出组成该序列的元素编号
- 动态规划——求最长下降/上升子序列
- 动态规划——求最长下降/上升子序列
- 【动态规划】最长上升子序列(LIS)
- 初入算法篇(动态规划)最长上升子序列poj2533+栈优化模板&&scau18090 好多好多球
- ZOJ 2432 Greatest Common Increasing Subsequence(最长公共上升子序列+路径打印)
- [ACM_动态规划] 最长上升子序列(LIS)
- UVALive2931 POJ1631 HDU1950 ZOJ1986 Bridging signals【最长上升子序列+二分+堆栈】
- UVa 111|History Grading|动态规划|最长上升子序列
- 九度OJ 1500 出操队形 -- 动态规划(最长上升子序列)
- DP经典应用(四)二维最长上升子序列问题——矩形嵌套问题