HDU 4512 最长公共上升子序列
各种序列复习:
(1)最长上升子序列。
1、这个问题用动态规划就很好解决了,设dp[i]是以第i个数字结尾的上升子序列的最长长度。那么方程可以是dp[i]=max(dp[j]+1)。(j<i)。复杂度为O(n^2);
2、另外有一个该经典问题的O(nlogn)算法。
首先知道,当求dp[i]时,如果出现a[k]<a[j],而dp[k]=dp[j]时,应当优先选k吧。那么,既然每次选的都是较小,就可以把字符串按照dp[t]=k这个子序列长度分类。当同样dp[t]=k时,记录下该长度的最小的a[p],设为数组d[k]。注意到d数组是单调不减的。为什么呢?因为假设当前是长度p,记录的位置就为d[p],如果出现d[q]>d[p],q<p,干脆就让以d[p]结尾的子序代替前面的。
于是有这个特点:
A、d[1]<=d[2]<=.......
那么,在每次更新dp[i]时,对于字符a[i],只需找出比它小的最大的k,使d[k]<a[i],不就可以了吗。然后更新dp[i]。对于查找,由于单调,很明显可以使用二分查找。
对于一个比较巧妙的写法。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = ;
int a[N]; //a[i] 原始数据
int d[N]; //d[i] 长度为i的递增子序列的最小值 int BinSearch(int key, int* d, int low, int high)
{
while(low<=high)
{
int mid = (low+high)>>;
if(key>d[mid] && key<=d[mid+])
return mid;
else if(key>d[mid])
low = mid+;
else
high = mid-;
}
return ;
} int LIS(int* a, int n, int* d)
{
int i,j;
d[] = a[];
int len = ; //递增子序列长度
for(i = ; i <= n; i++)
{
if(d[len]<a[i])
j = ++len;
else
j = BinSearch(a[i],d,,len) + ;
d[j] = a[i];
}
return len;
} int main()
{
int t;
int p;
scanf("%d",&t);
while(t--)
{
scanf("%d",&p);
for(int i = ; i <= p; i++)
scanf("%d",&a[i]);
printf("%d\n",LIS(a,p,d));
}
return ;
}
(2)最长公共子序列。
设dp[i][j]是第一个字符串以第i个结尾,第二个字符串以第j个结尾的长度。
那么就有dp[i][j]=max{dp[i-1][j],dp[i][j-1],dp[i-1][j-1]}。前两种情况针对a[i]!=a[j]的,后一种是针对相等的。
(3)最长公共上升子序列。
我介绍一种O(N(M^2))的算法,它将是我们向O(NM)进步的阶梯。我们设F[j]为必选择B[j]为末尾时的最长。。。子序列(懒得打),那么F[j] = Max{F[k]}+1,并且通过设置一个i变量来枚举A[i]。
var
f : array[..] of integer;
ans : integer;
procedure work2();
var
i,j,k:integer;
begin
for i:= to n do
for j:= to m do
if a[i] = b[j] then
for k:= to j- do
if b[k] < b[j] then
if f[j] < f[k]+ then
f[j]:=f[k]+;
for i:= to m do
if ans < f[i] then
ans:=f[i];
end;
此时我们把空间降到了一维。解释一下,k循环下面比较时,B[k]所对应的A[?]一定在A[i]以前,而k也小于j,这就保证了解的合法性。但注意到其中的k循环,这实际上是用来找最大值用的。那么我们想,为什么不把最大只保存起来呢?i循环没结束时不断更新这个k值就行了啊。那么下面的算法就出来了:
procedure work;
var
i,j,k:integer;
begin
for i:= to n do
begin
k:=;
for j:= to m do
begin
if a[i] = b[j] then
if f[j] < f[k]+ then
f[j]:=f[k]+;
if a[i] > b[j] then
if f[k] < f[j] then
k:=j; // 更新新的k
end;
end;
for i:= to m do
if ans < f[i] then
ans:=f[i];
end;
其实,对于上面的更新保存最大值的操作,为什么是可行的呢?
要知道,更新DP数组f是在a[i]==b[j]时才进行的,因为f数组定义的是以b[j]为结尾的最长序列。那么,由于是上升的,则必定是在结尾的字符之前b[k]<a[i]吧?那么,在扫描的过程中,就可以当满足
f[k] < f[j]时更新k了。 对于HDU 4512这道题,也就是最长公共上升子序列的模型。我以两个序列来模拟,一个顺序一个逆序。在代码中可以知道,对于以b[j]为结束序列,在最外层循环到i时,内层循环最多只能到n-i+1,为什么呢?因为两个序列是互逆的,当超出这个值时,它们之前的序列就可能交叉或重叠。当a[n-i+1]==b[j]&&n-不+1==j时,序列最长应该是奇数的。在求解过程中找出最长序列即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring> using namespace std; int num1[],num2[];
int f[]; int main(){
int T,n;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d",&num1[i]);
num2[n-i+]=num1[i];
}
memset(f,,sizeof(f));
int ans=;
for(int i=;i<=n;i++){
int k=;
for(int j=;j<=n-i+;j++){
if(num2[i]==num1[j]){
if(f[j] < f[k]+)
f[j]=f[k]+;
if(j==n-i+)
ans=max(ans,*f[j]-);
else {
ans=max(ans,*f[j]);
}
}
if(num2[i]>num1[j]){
if(f[k]<f[j])
k=j;
}
}
}
printf("%d\n",ans);
}
return ;
}
HDU 4512 最长公共上升子序列的更多相关文章
- hdu 1423 最长公共递增子序列 LCIS
最长公共上升子序列(LCIS)的O(n^2)算法 预备知识:动态规划的基本思想,LCS,LIS. 问题:字符串a,字符串b,求a和b的LCIS(最长公共上升子序列). 首先我们可以看到,这个问题具有相 ...
- hdu 1423 最长公共递增子序列
这题一开始把我给坑了,我还没知道LCIS的算法,然后就慢慢搞吧,幸运的是还真写出来了,只不过麻烦了一点. 我是将该题转换为多条线段相交,然后找出最多多少条不相交,并且其数值死递增的. 代码如下: #i ...
- codevs 2185 最长公共上升子序列
题目链接: codevs 2185 最长公共上升子序列codevs 1408 最长公共子序列 题目描述 Description熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目.小沐沐先让奶牛研究了最长上升 ...
- LCIS 最长公共上升子序列问题DP算法及优化
一. 知识简介 学习 LCIS 的预备知识: 动态规划基本思想, LCS, LIS 经典问题:给出有 n 个元素的数组 a[] , m 个元素的数组 b[] ,求出它们的最长上升公共子序列的长度. 例 ...
- 最长公共上升子序列(codevs 2185)
题目描述 Description 熊大妈的奶牛在小沐沐的熏陶下开始研究信息题目.小沐沐先让奶牛研究了最长上升子序列,再让他们研究了最长公共子序列,现在又让他们要研究最长公共上升子序列了. 小沐沐说,对 ...
- 最长公共上升子序列(LCIS)
最长公共上升子序列慕名而知是两个字符串a,b的最长公共递增序列,不一定非得是连续的.刚开始看到的时候想的是先用求最长公共子序列,然后再从其中找到最长递增子序列,可是仔细想一想觉得这样有点不妥,然后从网 ...
- ZOJ 2432 Greatest Common Increasing Subsequence(最长公共上升子序列+路径打印)
Greatest Common Increasing Subsequence 题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problem ...
- POJ 2127 最长公共上升子序列
动态规划法: #include <iostream> #include <cstdio> #include <fstream> #include <algor ...
- [CodeForces10D]LCIS(最长公共上升子序列) - DP
Description 给定两个数列,求最长公共上升子序列,并输出其中一种方案. Input&Output Input 第一行一个整数n(0<n<=500),数列a的长度. 第二行 ...
随机推荐
- 520D
模拟 很明显应该尽量选最大或最小的数.那么我们维护一个set,再维护一个mp,每次检查是否能选,如果选完这个数上面的东西不悬空就可以选,每次选完都要更新四周-2+2的方块,因为再远就影响不到了 #in ...
- Genuitec
- javascript必须知道的知识要点(二)
该文章不详细叙述各知识要点的具体内容,仅把要点列出来,供大家学习的时候参照,或者检测自己是否熟练掌握了javascript,清楚各个部分的内容. 内建对象可划分为数据封装类对象.工具类对象.错误类对象 ...
- A simple problem(并查集判环)
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2497 题意:给定一些点和边的关系,判断S点是否 ...
- selenium3 + python 操作浏览器基本方法
from selenium import webdriverimport time as t # driver = webdriver.Chrome()# driver.get("http: ...
- JDK多任务执行框架(Executor框架)
Executor的常用方法 为了更好的控制多线程,JDK提供了一套线程框架Executor,帮助开发人员有效地进行线程控制.它们都在java.util.concurrent包中,是JDK开发包的核心. ...
- mysql 年龄计算(根据生日字段)
mysql 年龄计算(根据生日字段) year( from_days( datediff( now( ), birthdate))) //获取年龄 now() 当前时间,精确到秒 datediff(b ...
- ACM_螺旋填数
螺旋填数 Time Limit: 2000/1000ms (Java/Others) Problem Description: 一天,小明在研究蜗牛的壳时,对其螺旋状的花纹感到十分有趣.于是他回到了家 ...
- B - String Task
Problem description Petya started to attend programming lessons. On the first lesson his task was to ...
- 记录一个MySQL的问题
昨天做asp.net mvc程序,用mysql.data.entity.ef6做数据连接. 程序都是正常的,但就是提交数据的时候总是提示 Specified key was too long; max ...