当前位置:文档之家› 求数组中最长递增子序列

求数组中最长递增子序列

求数组中最长递增子序列
求数组中最长递增子序列

求数组中最长递增子序列

写一个时间复杂度尽可能低的程序,求一个一维数组(N个元素)中的最长递增子序列的长度。

例如:在序列1,-1,2,-3,4,-5,6,-7中,其最长的递增子序列为1,2,4,6。

分析与解法

根据题目的要求,求一维数组中的最长递增子序列,也就是找一个标号的序列b[0],b[1],…,b[m](0 <= b[0] < b[1] < …< b[m] < N),使得array[b[0]]

解法一

根据无后效性的定义我们知道,将各阶段按照一定的次序排列好之后,对于某个给定的阶段状态来说,它以前各阶段的状态无法直接影响它未来的决策,而只能间接地通过当前的这个状态来影响。换句话说,每个状态都是历史的一个完整总结。

同样的,仍以序列1,-1,2,-3,4,-5,6,-7为例,我们在找到4之后,并不关心4之前的两个值具体是怎样,因为它对找到6没有直接影响。因此,这个问题满足无后效性,可以通过使用动态规划来解决。

可以通过数字的规律来分析目标串:1,-1,2,-3,4,-5,6,-7。

使用i来表示当前遍历的位置

当i=1时,显然,最长的递增序列为(1),序列长度为1.

当i=2是,由于-1<1。因此,必须丢弃第一个值后重新建立串。当前的递增序列为(-1),长度为1。

当i=3时,由于2>1,2>-1。因此,最长的递增序列为(1,2),(-1,2),长度为2。在这里,2前面是1还是-1对求出后面的递增序列没有直接影响。(但是在其它情况下可能有影响)

依此类推之后,我们得出如下的结论。

假设在目标数组array[]的前i个元素中,最长递增子序列的长度为LIS[i]。那么,

LIS[i+1]=max{1,LIS[k]+1},array[i+1]>array[k],for any k <= i

即如果array[i+1]大于array[k],那么第i+1个元素可以接在LIS[k]长的子序列后面构成一个更长的子序列。于此同时array[i+1]本身至少可以构成一个长度为1的子序列。

根据上面的分析,就可以得到代码清单

C++代码:

int Max(int *a, int n)

{

int max = a[0];

for(int i = 1; i < n; i++)

if(max < a[i])

max = a[i];

return max;

}

int LIS(vector &array)

{

int *a = new int[array.size()];

for(int i = 0; i < array.size(); i++)

{

a[i] = 1; //初始化默认的长度

for(int j = 0; j < i; j++) //前面最长的序列

{

if(array [i] > array [j] && a[j] + 1 > a[i])

{

a[i] = a[j] + 1;

}

}

}

return Max(a, array.size());

}

这种方法的时间复杂度为O(N2 + N) = O(N2)

解法二

在前面的分析中,当考察第i+1个元素的时候,我们是不考虑前面i个元素的分布情况的。现在我们从另一个角度分析,即当考察第i+1个元素的时候考虑前面i个元素的情况。

对于前面i个元素的任何一个递增子序列,如果这个子序列的最大的元素比array[i+1]小,那么就可以将array[i+1]加在这个子序列后面,构成一个新的递增子序列。

比如当i=4的时候,目标序列为1,-1,2,-3,4,-5,6,-7最长递增序列为(1,2),(-1,2)。

那么,只要4>2,就可以把4直接增加到前面的子序列中形成一个新的递增子序列。

因此,我们希望找到前i个元素中的一个递增子序列,使得这个递增子序列的最大的元素比array[i+1]小,且长度尽量地长。这样将array[i+1]加在该递增子序列后,便可以找到以array[i+1]为最大元素的最长递增子序列。

仍然假设在数组的前i个元素中,以array[i]为最大元素的最长递增子序列的长度为LIS[i]。

同时,假设:

长度为1的递增子序列最大元素的最小值为MaxV[1];

长度为2的递增子序列最大元素的最小值为MaxV[2];

……

长度为LIS[i]的递增子序列最大元素的最小值为MaxV[LIS[i]];

本循环不变式P是:

P:k是序列a[0:i]的最长递增子序列的长度,0≤i<n。

容易看出,在由i-1到i的循环中,a[i]的值起关键作用。如果a[i]能扩展序列a[0;i-1]的最长递增子序列的长度,则k=k+1,否则k不变。设a[0;i-1]中长度为k的最长递增子序列的结尾元素是a[j](0≤j≤i-1),则当a[i]≥a[j]时可以扩展,否则不能扩展。如果序列a[0;i-1]中有多个长度为k的最长递增子序列,那么需要存储哪些信息?容易看出,只要存储序列a[0;i-1]中所有长度为k的递增子序列中结尾元素的最小值b[k]。因此,需要将循环不变式P增强为:

P:0≤i<n;k是序列a[0;i]的最长递增子序列的长度;

b[k]是序列a[0;i]中所有长度为k的递增子序列中最小结尾元素值。

相应地,归纳假设也增强为:已知计算序列a[0;i-1](i<n)的最长递增子序列的长度k以及序列a[0;i]中所有长度为k的递增子序列中的最小结尾元素值b[k]的正确算法。

增强归纳假设后,在由i-1到i的循环中,当a[i]≥b[k]时,k=k+1,b[k]=a[i],否则k值不变。注意到当a[i]≥b[k]时,k值增加,b[k]的值为a[i]。那么,当a[i]<b[k]时,b[l;k]的值应该如何改变?如果a[i]

/* Finds longest strictly increasing subsequence. O(n log k) algorithm. */

template vector find_lis(vector &a)

{

vector b, p(a.size());//b是存储递增序列长度为k的最后元素下标

//比如b[1]是存储递增子序列最大元素的最小值的下标

//b是存储最长子序列的下标

int u, v;

if(a.size() < 1)

return b;

b.push_back(0);

for(int i = 1; i < (int)a.size(); i++)

{

if(a[b.back()] < a[i])

p[i] = b.back();

b.push_back(i);

continue;

}

for(u = 0, v = b.size()-1; u < v;) //二分搜索

{

int c = (u + v) / 2;

if(a[b[c]] < a[i])

u=c+1;

else

v=c;

}

if(a[i] < a[b[u]]) {

if(u > 0)

p[i] = b[u-1];

b[u] = i;

}

}

for(u = b.size(), v = b.back(); u--; v = p[v]) b[u] = v;

return b;

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

算法作业: LCS 问 题 作业要求:设计一个算法求出两个序列的所有LCS ,分析最坏情况,用“会计方法”证明利用b[i][j]求出 所有LCS 的算法在最坏情况下时间复杂度为)(m m n C O + 1、 算法思路: 根据最长公共子序列问题的性质,即经过分解后的子问题具有高度重复性,并且具有最优子结构性质,采用动态规划法求解问题。设X={x 1, x 2, … , x n }, Y={y 1, y 2, … , y m }, 首先引入二维数组C[i][j]记录X i 和Y j 的LCS 的长度,定义C[i][j]如下: { j i j y i 且x ,i,j ]][j C[i j y i x j i j i C j i C j i C 00001110,]},1][[],][1[max{]][[===>+--≠>--=或,且 为了构造出LCS ,还需要使用一个二维数组b[m][n],b[i][j]记录C[i][j]是通过哪个子问题的值求得 的,以决定搜索的方向,欲求出所有的LCS ,定义数组b 如下: 设1-对角线方向;2-向上;3-向左;4-向上或向左 若X[i]=Y[j],b[i][j] = 1, 若C[i-1][j][i][j-1], 则b[i][j] = 3, 若C[i-1][j]=[i][j-1], 则b[i][j] = 4, 根据以上辅助数组C 和b 的定义,算法首先需要求出这两个数组, C[m][n]中记录的最长公共子序列的长度,b 中记录了查找子序列元素的搜索方向。 利用C 和b 的信息,Find_All_LCS 可以采用回溯法求出所有的LCS 。基本思路如下:使用一个辅助数组记录每次调用Find_All_LCS 得到的LCS 中的元素,每次递归调用一次Find_All_LCS ,进入一个新的执行层,首先要判断当前处理的两个子序列长度是否大于等于0 ,若不满足,则该层的递归结束,返回上一层;然后再判断当前得到的子序列是否等于数组C 中求出的最长公共子序列长度,若等于,则说明算法执行到此已经得到一个LCS ,按序输出;若不等于,此时根据数组b 中记录的搜索方向继续搜索,特别要说明的是,当b[i][j]=4时,即要向上或向左,需要对这两个方向分别调用Find_All_LCS ,保证沿着这两个方向上LCS 元素不被漏掉,都可以搜索到;若b[i][j]=1,即沿对角线方向搜索前进时,此时元素X[i]为LCS 中的元素,存放至辅助数组中去,同时将当前已经求得的LCS 长度增1,当递归调用Find_All_LCS 从b[i][j]=1处时,需要回溯一步,搜索其它路径上可能为LCS 中的元素。当所有的可能路径都已经搜索完,算法结束。 对于某些情况会输出重复的LCS ,这是因为算法在沿不同路径搜索时可能会出现相同的LCS 序列。 2、 时间复杂度分析 由上述对Find_All_LCS 算法的分析可知,求出所有的LCS 实际上是根据搜索的方向信息遍历所有的路径找出满足条件的元素集合。因此,除求解辅助数组C 和b 所用的O(mn+m+n)的执行时间外,Find_All_LCS 的时间复杂度取决于所遍历路径数。而路径数是由搜索方向决定的。显然算法在最好的情况下,即m=n 并且b 中所有的值都指示沿着对角线方向搜索,时间复杂度为O(n). 相反,当X 和Y 序列不存在公共子序列时为算法的最坏情况,此时C 中所有值都等于0,数组b 中所有的值都指示要分别沿两个不同的方向(向左或向上)搜索,这种情况下每处理一次X[i],Y[j]时总是要沿两个方向分别调用Find_All_LCS ,遇到i=0或j=0时返回,直到搜索完所有的可能路径才结束,最坏情况下的搜索矩阵如下图所示:

求最长子序列的长度

一,最长递增子序列问题的描述 设L=是n个不同的实数的序列,L的递增子序列是这样一个子序列Lin=,其中k1是对序列L=按递增排好序的序列。那么显然X与L的最长公共子序列即为L的最长递增子序列。这样就把求最长递增子序列的问题转化为求最长公共子序列问题LCS了。 最长公共子序列问题用动态规划的算法可解。设Li=< a1,a2,…,a i>,Xj=< b1,b2,…,b j>,它们分别为L和X的子序列。令C[i,j]为Li与Xj的最长公共子序列的长度。则有如下的递推方程: 这可以用时间复杂度为O(n2)的算法求解,由于这个算法上课时讲过,所以具体代码在此略去。求最长递增子序列的算法时间复杂度由排序所用的O(nlogn)的时间加上求LCS的O(n2)的时间,算法的最坏时间复杂度为O(nlogn)+O(n2)=O(n2)。 三,第二种算法:动态规划法 设f(i)表示L中以a i为末元素的最长递增子序列的长度。则有如下的递推方程: 这个递推方程的意思是,在求以a i为末元素的最长递增子序列时,找到所有序号在L前面且小于a i的元素a j,即j

最长公共子序列实验报告

河北地质大学课程设计报告 (学院)系: 信息工程学院 专业: 计算机科学与技术 姓名: 李义 班级: 二班 学号: 515109030227 指导教师: 王培崇 2016年11月26 日

算法课程设计报告 姓名李义学号515109030227 日期2016/11/10-2016/12/1 实验室152 指导教师王培崇设备编号08 设计题目求最长公共子序列 一、设计内容 求最长公共子序列,如输入字符串str1=adadsda,str2=sadasfda。 则求出的最长公共子序列是adasda。 二、设计目的 掌握动态规划思想,对使用求最长公共子序列加深理解。 三、设计过程 1.算法设计 1. for i ←0 to n 2. L[i,0] ←0 3. end for 4. for j ←0 to m 5. L[0,j] ←0 6. end for 7. for i ←1 to n 8. for j ←1 to m 9. if ai=bj then L[i,j]←L[i-1,j-1]+1 10. else L[i,j]←max {L[i,j-1], L[i-1,j] } 11. end if 12. end for 13. end for 14. return L[n,m] 2.流程图

开始结束 输入I=0,j=0 i<=n L[I,0]=0 i++ Y L[0,j]=0 N j<=n j++ Y i=1 to n J=1 to m ai=bj L[i,j]=L[i-1,j-1]+1 L[i,j]=max{L[i-1,j ],L[i,j-1]} Y J++i++ N 图1.Lcs 算法 3.数据结构 str1=adadsda str2=sadasfda 四、程序实现及运行结果

动态规划解最长公共子序列问题

动态规划解最长公共子序列问题 动态规划主要针对最优化问题,它的决策是全面考虑不同的情况分别进行决策,,最后通过多阶段决策逐步找出问题的最终解.当各个阶段采取决策后,会不断决策出新的数据,直到找到最优解.每次决策依赖于当前状态,又随机引起状态的转移.一个决策序列就是在变化的状态中产生出来的,故有”动态”的含义.所以,这种多阶段最优化决策解决问题的过程称为动态规划. 一问题的描述与分析 字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干字符(可能一个也不去掉)后形成的字符序列..令给定的字符序列X=”x0,x1,x2,…xm-1”,序列Y=”y0,y1,…yk-1”是X的子序列,存在X的一个严格递增下标序列i=i0,i1,i2,…ik-1,使得对所有的j=0,1,2,…k-1,有xi=yi。例如X=“ABCBDAB”,Y=“BCDB”是X的一个子序列。 给定两个序列A和B,称序列Z是A和B公共子序列,是指Z同是A和B的子序列。求最长公共子序列。 若A的长度为m,B的长度为n,则A的子序列有2*m-1个,B的子序列有2*n-1个。采用枚举法分别对A和B的所以子序列一一检查,最终求出最长公共子序列。如此比较次数(2*2n)接近指数阶,当n较大时,算法太耗时,不可取。所以要全面考虑不同的情况分别进行决策,,最后通过多阶段决策逐步找出问题的最终解.当各个阶段采取决策后,会不断决策出新的数据,直到找到最优解。 二、算法设计(或算法步骤) A=”a0,a1,a2,……am-1”,B=”b0,b1,b2,……bn-1”,且Z=”z0,z1,z2……zk-1”,为她们的最长公共子序列。不难证明有一下结论: (1)如果am-1=bn-1,则zk-1=am-1=bn-1,且“z0,z1,z2,……zk-2”是“a0,a1,a2,…… am-2”和“b0,b1,b2,……bn-2”的一个最长公共子序列; (2)如果am-1!=bn-1,则若zk-1!=am-1,则“z0,z1,z2,……zk-1”是“a0,a1,a2,…… am-2”和”b0,b1,b2,……bn-1”的一个最长公共子序列。 (3)如果am-1!=bn-1,则若zk-1!=bn-1,则“z0,z1,z2,……zk-1”是“a0,a1,a2,…… am-1”和“b0,b1,b2,……bn-2”的一个最长公共子序列。 如此找到了原问题与其子问题的递归关系。 基本存储结构是存储两个字符串及其最长公共子序列的3个一位数组。当然要找出最长公共子序列,要存储当前最长公共子序列的长度和当前公共子序列的长度,而若只存储当前信息,最后只能求解最长公共子序列的长度,却不能找到最长公共子序列本身。因此需建立一个(n+1)*(m+1)的二维数组c,c[i][j]存储序列“a0,a1,a2……ai-2”和“b0,b1,……bj-1”的最长公共子序列长度,由上递推关系分析,计算c[i][j]可递归的表述如下: (1)c[i][j]=0 如果i=0或j=0;

最长公共子序列问题

2.3最长公共子序列问题 和前面讲的有所区别,这个问题的不涉及走向。很经典的动态规划问题。 例题16 最长公共子序列 (lcs.pas/c/cpp) 【问题描述】 一个给定序列的子序列是在该序列中删去若干元素后得到的序列。确切地说,若给定序列X= < x1, x2,…, xm>,则另一序列Z= < z1, z2,…, zk>是X的子序列是指存在一个严格递增的下标序列< i1, i2,…, ik>,使得对于所有j=1,2,…,k有Xij=Zj 例如,序列Z=是序列X=的子序列,相应的递增下标序列为<2,3,5,7>。给定两个序列X 和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。例如,若X= < A, B, C, B, D, A, B>和Y= < B, D, C, A, B, A>,则序列是X和Y的一个公共子序列,序列也是X和Y的一个公共子序列。而且,后者是X和Y的一个最长公共子序列,因为X和Y没有长度大于4的公共子序列。 给定两个序列X= < x1, x2, …, xm>和Y= < y1, y2, … , yn>,要求找出X和Y的一个最长公共子序列。 【输入文件】 输入文件共有两行,每行为一个由大写字母构成的长度不超过200的字符串,表示序列X和Y。 【输出文件】 输出文件第一行为一个非负整数,表示所求得的最长公共子序列的长度,若不存在公共子序列,则输出文件仅有一行输出一个整数0,否则在输出文件的第二行输出所求得的最长公共子序列(也用一个大写字母组成的字符串表示。 【输入样例】 ABCBDAB BDCBA 【输出样例】 4 BCBA 【问题分析】 这个问题也是相当经典的。。 这个题目的阶段很不明显,所以初看这个题目没什么头绪,不像前面讲的有很明显的上一步,上一层之类的东西,只是两个字符串而且互相没什么关联。 但仔细分析发现还是有入手点的: 既然说是动态规划,那我们首先要考虑的就是怎么划分子问题,一般对于前面讲到的街道问题和数塔问题涉及走向的,考虑子问题时当然是想上一步是什么?但这个问题没有涉及走向,也没有所谓的上一步,该怎么办呢? 既然是求公共子序列,也就有第一个序列的第i个字符和第二个序列的第j个字符相等的情况。 那么我们枚第一个序列(X)的字符,和第二个序列(Y)的字符。 显然如果X[i]=Y[j]那么起点是1(下面说的子序列都是起点为1的),长度为i的子序列和长度为j的子序列的最长公共子序列就是长度为i-1和长度为j-1 的子序列中最长的公共子

最长公共子序列问题

实验三最长公共子序列问题 1.实验环境 本实验采用 java 语言编写实现,环境:,编译器: eclipse 2.实验目的 通过最长公共子序列问题,巩固并详细分析动态规划思想和解题 步骤。 3.设计思路 最长公共子序列的定义为:设有两个序列S[1..m]和9[仁n],需要寻找它们之间的一个最长公共子序列。 例如,假定有两个序列: S1: I N T H E B E G I N N I N G S2: A L L T H I N G S A R E L O S T 则S i和S的一个最长公共子序列为 THING又比如: S1: A B C B D A B S2: B D C A B A 则它们的一个最长公共子序列为 BCBA。 这里需要注意的是,一个子序列不一定必须是连续的,即中间可被其他字符分开,单它们的顺序必须是正确的。另外,最长公共子序列不一定只有一个,而我们需要寻找的是其中一个。

当然,如果要求子序列里面的元素必须连成一片也是可以的。实际上,连成一片的版本比这里实现的更容易。 4.过程 我们可以通过蛮力策略解决这个问题,步骤如下: 1.检查S1[1..m]里面每一个子序列。 2.看看其是否也是S2[1..n]里的子序列。 3.在每一步记录当前找到的子序列里面最长的子序列。 这种方法的效率十分低下。因此本实验采用动态规划的方法实现该算法。 利用动态规划寻找最长公共子序列步骤如下: 1.寻找最长公共子序列的长度。 2.扩展寻找长度的算法来获取最长公共子序列。 策略:考虑序列S1和S2的前缀序列。 设 c[i,j] = |LCS (S1[1..i],S2[1..j]),则有 c[m, n] = |LCS(S1 S2)| 所以有 c[ i -1 , j -1 ] + 1, 如要 S1[i] = S2[j] c[i, j]= max{ c [ i - 1, j ], c[ i , j -1 ] }, 如果 S1[i]工S2[j] 然后回溯输出最长公共子序列过程:

最长公共子序列实验报告

最长公共子序列问题 一.实验目的: 1.加深对最长公共子序列问题算法的理解,实现最长公共子序列问题的求解算法; 2.通过本次试验掌握将算法转换为上机操作; 3.加深对动态规划思想的理解,并利用其解决生活中的问题。 二.实验内容: 1.编写算法:实现两个字符串的最长公共子序列的求解; 2.将输入与输出数据保存在文件之中,包括运行时间和运行结果; 3.对实验结果进行分析。 三.实验操作: 1.最长公共子序列求解: 将两个字符串放到两个字符型数组中,characterString1和characterString2,当characterString1[m]= characterString2[m]时,找出这两个字符串m之前的最长公共子序列,然后在其尾部加上characterString1[m],即可得到最长公共子序列。当characterString1[m] ≠characterString2[m]时,需要解决两个子问题:即找出characterString1(m-1)和characterString2的一个最长公共子序列及characterString1和characterString2(m-1)的一个最长公共子序列,这两个公共子序列中较长者即为characterString1和characterString2的一个最长公共子序列。 2.动态规划算法的思想求解: 动态规划算法是自底向上的计算最优值。 计算最长公共子序列长度的动态规划算法LCS-Length以characterString1和characterString2作为输入,输出两个数组result和judge1,其中result存储最长公共子序列的长度,judge1记录指示result的值是由那个子问题解答得到的,最后将最终的最长公共子序列的长度记录到result中。 以LCS-Length计算得到的数组judge1可用于快速构造序列最长公共子序列。首先从judge1的最后开始,对judge1进行配对。当遇到“↖”时,表示最长公共子序列是由characterString1(i-1)和characterString2(j-1)的最长公共子序列在尾部加上characterString1(i)得到的子序列;当遇到“↑”时,表示最长公共子序列和characterString1(i-1)与characterString2(j)的最长公共子序列相同;当遇到“←”时,表示最长公共子序列和characterString1(i)与characterString2(j-1)的最长公共子序列相同。 如图所示:

《递增序列》解题报告

《递增序列》解题报告 问题简述 有一个长度为n 的非负整数序列A 。要求修改尽量少的元素使其变成另一个非负整数序列B ,且序列B 是严格递增的。在修改元素尽量少的情况下使得序列B 的元素之和尽量小。 (110000)n ≤≤ 分析 要修改尽量少的元素使得序列A 单调递增,就是使尽量多的元素不要改动。显然这些没有改动的元素是满足单调递增的,于是想到求出序列A 的最长单调上升子序列,这些元素不变,对其它元素进行修改。 很容易发现,这个算法是错误的,因为如果单调上升子序列中相邻的两个元素在原序列A 之间的元素个数大于这两个元素中间能插入的元素个数,则无法进行修改。比如序列A 为(1,6,5,3,4),最长单调上升子序列为(1,3,4),那么1和3之间只能插入一个2,却有6和5两个元素,无法满足条件。 如果能把条件稍加修改,将单调递增改成非递减,显然上面的问题就不复存在了。定义: 序列C :()(1) 1i i C A i i n =--≤≤ 序列D :()(1)1i i D B i i n =--≤≤ 显然序列A 与序列C ,序列B 与序列D 都是一一对应的。当序列D 满足非递减时,即()111i i D D i n +≤≤≤-,则()11111i i i i D i B B D i i n +++-=<=+≤≤-。所以一个非递减的序列D 就一一对应了一个单调递增序列B 。而且11(1)2 n n i i i i n n B D ==--= ∑∑是一个常数,所以元素之和最小的非递减序列D 就对应了问题要求的元素之和最小的单调递增序列B 。 问题转化为,如何通过序列C 修改尽量少的元素,得到一个非递减的序列D ,在修改元素尽量少的情况下使得序列D 的元素之和尽量小。 因为序列B 是一个非负整数序列,又满足单调递增,所以

最长递增子序列

var a,f{DP记录},p{后面的}:array[1..1000]of longint; i,j,k,n:longint; begin readln(n); for i:=1 to n do begin read(a[i]); f[i]:=1;{预处理} end; for i:=n-1 downto 1 do for j:=n downto i+1 do if (a[i]j then begin j:=f[i]; k:=i; end; writeln(j); while k<>0 do begin write(k,' '); k:=p[k]; end; end. 最长上升子序列的nlog(n)算法 [ 2007-7-7 8:26:00 | By: TINYWOLF ] 听说程序是cqf大牛d ^_^ 刚开始一看,以为a数组是用来保存元素的,呵呵, 特点1:每次输入一个元素都要进行处理,以求维护好整个数组。那为什么要维护要整个数组呢? 假设最长可以达到i,那么1a[c-1]) a[c++]=t;

如果不是呢,那t要插进数组里面去,代替一个没有必要存在的元素,为什么说它没有必要呢? 比如 1 3 5 6 7 8 4 6 9 前面都是比较顺,所以一下子积累到了1 3 5 6 7 8 ,接着来了一个4这个4要代替5,而且这样做一点都不影响最后的结果(只会变好不会变坏)因为如果后来再来一个5就可以代替6的位置了,哈哈,下来的工作就交给cqf大牛的程序了 ^_^ - 特点2:二分那里,一来为了更快找到代替元素,而来要注意上下指针的改变不一样,要代替的是比自己刚好大那么一dd(最小)的那个。 #i nclude #i nclude int main() { int a[40005],c,m,n,i,k,t; scanf("%d",&m); while(m-->0) { scanf("%d",&n); if(n==0){printf("0\n");continue;} for(i=0;i<=n+2;i++)a[i]=0; c=1; scanf("%d",&t); a[0]=t; for(k=1;ka[c-1]) a[c++]=t; else { int l=0,h=c-1,mid=(l+h)/2; while(lt)h=mid; mid=(l+h)/2; } a[mid]=t; } } printf("%d\n",c); } return 0; } Zju 1986 Bridging Signals

动态规划法求解最长公共子序列(含Java代码)

公共子序列问题徐康123183 一.算法设计 假设有两个序列X和Y,假设X和Y分别有m和n个元素,则建立一个二维数组C[(m+1)*(n+1)],记录X i与Y j的LCS的长度。将C[i,j]分为三种情况: 若i =0 或j =0时,C[i,j]=0; 若i,j>0且X[i]=Y[j],C[i,j]=C[i-1,j-1]+1; 若i,j>0且X[i] Y[j],C[i,j]=max{C[i-1,j],C[i,j-1]}。 再使用一个m*n的二维数组b,b[i,j]记录C[i,j]的来向: 若X[i]=Y[j],则B[i,j]中记入“↖”,记此时b[i,j] = 1; 若X[i] Y[j]且C[i-1,j] > C[i,j-1],则b[i,j]中记入“↑”,记此时B[i,j] = 2; 若X[i] Y[j]且C[i-1,j] < C[i,j-1],则b[i,j]中记入“←”,记此时B[i,j] = 3; 若X[i]Y[j]且C[i-1,j] = C[i,j-1],则b[i,j]中记入“↑”或“←”,记此时B[i,j] = 4; 得到了两个数组C[]和B[],设计递归输出LCS(X,Y)的算法: LCS_Output(Direction[][], X[], i, j, len,LCS[]){ If i=0 or j=0 将LCS[]保存至集合LCS_SET中 then return; If b[i,j]=1 then /*X[i]=Y[j]*/ {LCS_Output(b,X,i-1,j-1); 将X[i]保存至LCS[len-i];} else if b[i,j]=2 then /*X[i]Y[j]且C[i-1,j]>C[i,j-1]*/ LCS_Output(b,X,i-1,j) else if b[i,j]=3 then /*X[i]Y[j]且C[i-1,j]

2014年下半年软件设计师考试下午真题(含答案)

2014年下半年软件设计师下午试题 试题:1 阅读下列说明和图,回答问题1至问题3,将解答填入答题纸的对应栏内。 【说明】 某大型披萨加工和销售商为了有效管理生产和销售情况,欲开发一披萨信息系统, 其主要功能如下: (1)销售。处理客户的订单信息,生成销售订单,并将其记录在销售订单表中。销售订单记录了订购者、所订购的披萨、期望的交付日期等信息。 (2)生产控制。根据销售订单以及库存的披萨数量,制定披萨生产计划(包括生产哪些披萨、生产顺序和生产量等),并将其保存在生产计划表中。 (3)生产。根据生产计划和配方表中的披萨配方,向库存发出原材料申领单,将制作好的披萨的信息存入库存表中,以便及时进行交付。 (4)采购。根据所需原材料及库存量,确定采购数量,向供应商发送采购订单,并将其记录在采购订单表中;得到供应商的供应量,将原材料数量记录在库存表中,在采购订单表中标记已完成采购的订单。 (5)运送。根据销售订单将披萨交付给客户,并记录在交付记录表中。 (6)财务管理。在披萨交付后,为客户开具费用清单,收款并出具收据;依据完成的采购订单给供应商支付原材料费用并出具支付细节;将收款和支付记录存入收支记录表中。 (7)存储。检查库存的原材料、拔萨和未完成订单,确定所需原材料。 现采用结构化方法对披萨信息系统进行分析与设计,获得如图1-1所示的上下文数据流图和图1-2所示的0层数据流图。 图1-1 上下文数据流图

图1-2 0层数数据流图 【问题1】(4分) 根据说明中的词语,给出图1-1中的实体E1~E2的名称。 E1: 客户E2: 供应商 【问题2】(5分) 根据说明中的词语,给出图1-2中的数据存储D1~D5的名称。 D1: 销售订单表D2: 库存表D3: 生产计划表D4: 原材料申领单D5: 采购订单表 【问题3】(6分) 根据说明和图中词语,补充图1-2中缺失的数据流及其起点和终点。 1:数据流名称:支付细节起点:4 终点:E2 2:数据流名称:生产计划起点:D3 终点:3 3:数据流名称:库存量起点:7 终点:4 4:数据流名称:原材料数量起点:4 终点:D2 5:数据流名称:交付起点:D1 终点:5

最长公共子序列

动态规划

一、问题描述 用动态规划法求两个字符串A=‘xzyzzyx’和B=‘zxyyzxz’的最长公共子序列 二、算法分析 (1)、若xm=yn,则zk=xm=yn,且Zk-1是Xm-1和Yn-1的最长公共自序列; (2)、若xm≠yn,且zk≠xm,则Zk是Xm-1和Yn的最长公共自序列; (3)、若xm≠yn,且zk≠yn,则Zk是Xm和Yn-1的最长公共自序列;设L(m,n)表示序列X={x1,x2,…,xm}和Y={y1,y2,…,yn}的最长公共子序列的长度 L表示已经决策的长度 S表示每个决策的状态 L(0,0)=L(0,j)=0 1≤i≤m, 1≤j≤n L(i-1,j-1)+1 xi=yi,i≥1,j≥1 L(i,j)= max{L(i,j-1),(L(i-1,j)} xi≠yi,i≥1,j≥1 1 xi=yi S(i,j)= 2 xi≠yi 且L(i,j-1)≥L(i-1,j) 3 xi≠yi 且L(i,j-1)< L(i-1,j)

长度矩阵L 三、源代码 #include #include using namespace std; int main() { string str1 = "xzyzzyx"; string str2 = "zxyyzxz"; int x_len = str1.length(); int y_len = str2.length();

int arr[50][50] ={{0,0}}; int i = 0; int j = 0; for(i = 1; i <= x_len; i++) { for(j = 1; j <= y_len; j++) { if(str1[i - 1] == str2[j - 1]) { arr[i][j] = arr[i - 1][j - 1] + 1; } else if(arr[i][j - 1] >= arr[i - 1][j]) arr[i][j] = arr[i][j - 1]; else arr[i][j] = arr[i -1][j]; } } for(i = 0 ; i <= x_len; i++) {

求数组中最长递增子序列

求数组中最长递增子序列 写一个时间复杂度尽可能低的程序,求一个一维数组(N个元素)中的最长递增子序列的长度。 例如:在序列1,-1,2,-3,4,-5,6,-7中,其最长的递增子序列为1,2,4,6。 分析与解法 根据题目的要求,求一维数组中的最长递增子序列,也就是找一个标号的序列b[0],b[1],…,b[m](0 <= b[0] < b[1] < …< b[m] < N),使得array[b[0]]1,2>-1。因此,最长的递增序列为(1,2),(-1,2),长度为2。在这里,2前面是1还是-1对求出后面的递增序列没有直接影响。(但是在其它情况下可能有影响) 依此类推之后,我们得出如下的结论。 假设在目标数组array[]的前i个元素中,最长递增子序列的长度为LIS[i]。那么, LIS[i+1]=max{1,LIS[k]+1},array[i+1]>array[k],for any k <= i 即如果array[i+1]大于array[k],那么第i+1个元素可以接在LIS[k]长的子序列后面构成一个更长的子序列。于此同时array[i+1]本身至少可以构成一个长度为1的子序列。 根据上面的分析,就可以得到代码清单 C++代码: int Max(int *a, int n) { int max = a[0]; for(int i = 1; i < n; i++) if(max < a[i])

最长公共子序列LCS 问题的matlab实现代码

(以下代码可直接带入matlab运行,首先以.m文件保存第一段代码,然后在command window输入第二段代码即可) function D=substringArray(A,B) na=length(A); nb=length(B); C=zeros(nb,na); for i=1:nb C(i,1)=0; end for j=1:na C(1,j)=0; end for i=2:nb for j=2:na if B(i-1)==A(j-1) C(i,j)=C(i-1,j-1)+1; else if C(i-1,j)>=C(i,j-1) C(i,j)=C(i-1,j); else C(i,j)=C(i,j-1); end end end end valmax=C(nb,na); i=nb; j=na; D=''; while i>1 & j>1 if C(i,j)==C(i-1,j-1)+1 & A(j-1)==B(i-1) D=strcat(B(i-1),D) ; i=i-1; j=j-1; else if C(i,j)==C(i,j-1) j=j-1; else i=i-1; end end end

%A='ACGTAACCT'; %B='GGACTTAGG'; %A='abcbs'; %B='bcabf'; A=getgenbank('NC_002017','SEQUENCEONLY',true); B=getgenbank('NC_002018','SEQUENCEONLY',true); substring=substringArray(A,B)

算法设计期中试卷平时作业参考解答

《算法分析与设计》2012-2013-2学期期中测试(信息安全专业DQ 教学班) 姓名: 学号: 得分: 1. 证明()()()()()()()O f n O g n O f n g n +=+。(10分) 证明:对于任意f 1(n ) ∈ O (f (n )),存在正常数c 1和自然数n 1,使得对所有n ≥ n 1,有f 1(n ) ≤ c 1f (n )成立。 类似,对于任意g 1(n ) ∈ O (g (n )),存在正常数c 2和自然数n 2,使得对所有n ≥ n 2,有g 1(n ) ≤ c 2g (n )成立。 令c 3 = max{c 1, c 2},n 3 = max{n 1, n 2},则对所有的n ≥ n 3,有 f 1(n ) +g 1(n ) ≤ c 1f (n ) + c 2g (n ) ≤ c 3f (n ) + c 3g (n ) = c 3(f (n ) + g (n )) 即()()()()()()()O f n O g n O f n g n +=+成立。 2. 将下列5个函数按渐近增长率由低至高进行排序,要求写出比较过程。(15分) 100log 2log loglog 12345()(log ),()log ,()log ,()2,()n n n n f n n n f n n f n n n f n f n +===== 解: 100log 2log log log 24()log 100log ,()2log ,n n n f n n n f n n n +==== (1) 2()f n 是对数函数的幂,5()f n 是幂函数,因此()25()()f n O f n =; (2) ()()()491105log lim lim lim log n n n f n n n n n f n n →∞ →∞→∞===∞,因此()54()()f n O f n =; (3) ()() 423log 1lim lim lim 0log n n n f n n n f n n n n →∞ →∞→∞===,因此()43()()f n O f n =; (4) 对1()f n 和3()f n 取对数,有 ()()() 13log ()log loglog loglog ,log ()2log loglog log f n n n n n n n f n n n n =+=Θ=Ω=+=Θ, 因为()log n O n =,所以()31()()f n O f n =; 因此,5个函数按渐近增长率由低至高排序为25431(),(),(),(),()f n f n f n f n f n 。 3. 给定按升序排列的n 个不同整数存于数组a [1:n ]中,请设计()log O n 的算法找到下标i ,1i n ≤≤,使得a [i ] = i ,如不存在这样的下标,则返回0。(15分) 解: 令head = 1, rear = n . (1) 当head <= rear 时,令mid = ?(head + rear)/2?; (2) 如果a [mid] = mid ,返回mid 值,结束。 如果a [mid] > mid ,令rear = mid – 1,返回(1)继续执行; 如果a [mid] < mid ,令head = mid + 1,返回(1) 继续执行; (3)返回0值,结束。

最长公共子序列问题

1. 实验环境 本实验采用java语言编写实现,环境:,编译器:eclipse 2. 实验目的 通过最长公共子序列问题,巩固并详细分析动态规划思想和解题步骤。 3. 设计思路 最长公共子序列的定义为:设有两个序列S1[1..m]和S2[1..n],需要寻找它们之间的一个最长公共子序列。 例如,假定有两个序列: S1:I N T H E B E G I N N I N G S2:A L L T H I N G S A R E L O S T 则S1和S2的一个最长公共子序列为THING。又比如: S1:A B C B D A B S2:B D C A B A 则它们的一个最长公共子序列为BCBA。 这里需要注意的是,一个子序列不一定必须是连续的,即中间可被其他字符分开,单它们的顺序必须是正确的。另外,最长公共子序列不一定只有一个,而我们需要寻找的是其中一个。 当然,如果要求子序列里面的元素必须连成一片也是可以的。实际上,连成一片的版本比这里实现的更容易。

4. 过程 我们可以通过蛮力策略解决这个问题,步骤如下: 1. 检查S1[1..m]里面每一个子序列。 2. 看看其是否也是S2[1..n]里的子序列。 3. 在每一步记录当前找到的子序列里面最长的子序列。 这种方法的效率十分低下。因此本实验采用动态规划的方法实现该算法。 利用动态规划寻找最长公共子序列步骤如下: 1. 寻找最长公共子序列的长度。 2. 扩展寻找长度的算法来获取最长公共子序列。 策略:考虑序列S1和S2的前缀序列。 设c[i,j] = |LCS (S1[1..i],S2[1..j])|,则有c[m,n] = |LCS(S1,S2)| 所以有 c[ i – 1 , j – 1 ] + 1,如要S1[i] = S2[j] c[i,j] = max{ c [ i - 1,j ],c[ i ,j -1 ] },如果S1[i]≠S2[j] 然后回溯输出最长公共子序列过程:

2017上半年程序员下午题

1 阅读以下说明和流程图,填补流程图中的空缺,将解答填入答题纸的对应栏内。【说明】下面流程图的功能是:在给定的一个整数序列中查找最长的连续递增子序列。设序列存放在数组A[1:n](n≥2)中,要求寻找最长递增子序列A[K:K+L一1](即A[K]<A[K+1]<…<A[K+L一1])。流程图中,用Kj和Lj分别表示动态子序列的起始下标和长度,最后输出最长递增子序列的起始下标K和长度L。例如,对于序列A={1,2,4,4,5,6,8,9,4,5,8},将输出K=4,L=5。【流 程图】注:循环开始框内应给出循环控制变量的初值和终值,默认递增值为1,格式为:循环控制变量=初值,终值 2 阅读以下说明和C代码,填补代码中的空缺,将解答填入答题纸的对应栏内。【说明】 下面的代码运行时,从键盘输入一个四位数(各位数字互不相同,可以有0),取出组成该四位数的每一位数,重组成由这四个数字构成的最大四位数max4和最小四位数min4(有0时为三位数),计算max4与min4的差值,得到一个新的四位数。若该数不等于6174,则重复以上过程,直到得到6174为止。 例如,输入1234,则首先由4321-1234,得到3087;然后由8730-378,得到8352;最后由8532-2358,得到6174。 【C代码】

#include int difference(int a[]) { int t,i,j,max4,min4; for(i=0;i<3;i++){/*用简单选择排序法将a[0]~a[3]按照从大到小的顺序排列*/ t=i; for(j=i+1;___________(1);j++) if(a[j]>a[t])__________(2); if(t!=i) { int temp=a[t]; a[t]=a[i]; a[i]=temp; } } max4=___________(3); min4=___________(4); return max4-min4; } int main() { int n,a[4]; printf("input a positive four-digit number:"); Scanf("%d",&n); while(n!=6174){ a[0]=__________(5);/*取n的千位数字*/ a[1]=n/100%10;/*取n的百位数字*/ a[2]=n/10%10;/*取n的十位数字*/ a[3]=__________(6);/*取n的个位数字*/ n=difference(a); } return 0; } 3 阅读以下说明和C代码,填补代码中的空缺,将解答填入答题纸的对应栏内。【说明】 对一个整数序列进行快速排序的方法是:在待排序的整数序列中取第一个数作为基准值,然后根据基准值进行划分,从而将待排序列划分为不大于基准值者(称为左子序列)和大于基准值者(称为右子序列),然后再对左子序列和右子序列分别进行快

用动态规划法解决最长公共子序列问题

动态规划解最长子序列 一、课程设计目的 掌握动态规划法的原理,并能够按其原理编程实现求两个序列数据的最长公共子系列,以加深对其的理解。 二、课程设计内容 1、用动态规划法解决最长子序列问题 2、交互输入两个序列数据 3、输出两个序列的最长公共子序列 三、概要设计 四、详细设计与实现 #include "iostream.h" #include "iomanip.h" #define max 100 void LCSLength(int m,int n,char *x,char *y,char *b) { int i,j,k; int c[max][max]; for(i=1;i<=m;i++) { c[i][0]=0; } for(i=1;i<=n;i++) { c[0][i]=0; } for(i=1;i<=m;i++) { for(j=1;j<=n;j++) { if(x[i-1]==y[j-1]) { c[i][j]=c[i-1][j-1]+1; k=i*(n+1)+j; b[k]='\\'; } else if(c[i-1][j]>=c[i][j-1]) {

c[i][j]=c[i-1][j]; k=i*(n+1)+j; b[k]='|'; } else{ c[i][j]=c[i][j-1]; k=i*(n+1)+j; b[k]='-'; } } } } void LCS(int i,int j,char *x,char *b,int width) { if(i==0 || j==0) return; int k=i*(width+1)+j; if(b[k]=='\\'){ LCS(i-1,j-1,x,b,width); cout<

相关主题
文本预览
相关文档 最新文档