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的长度. 第二行 ...
随机推荐
- Device /dev/sdb1 not found (or ignored by filtering)
/etc/lvm/lvm.conf filters
- Jmeter_Beanshell解析并提取json响应
1:前置条件 将fastjson-1.2.49.jar包置于jmeter的lib目录下,并将该jar包添加到测试计划的Library中:否则会报:Typed variable declaration ...
- File入门及路径名问题
package com.io.file; import java.io.File; /** * @author 王恒 * @datetime 2017年4月20日 下午2:53:29 * @descr ...
- System.net.mail发送电子邮件
之前做的实现发送邮件的功能,基于System.net.mail,在本地测试是可以发送邮件的,发布到服务器上发送不了邮件,后来发现STMP默认使用25端口收发邮件,服务器封掉25了端口,导致发送邮件失败 ...
- Android几种常见的多渠道(批量)打包方式介绍
多渠道打包,主要是为了统计不同的渠道上包的下载数量,渠道越多,我们需要打的包数量越多,这个时候,我们没法去使用单纯的手动打包去一个一个的生成不同的渠道包,我们需要更高效的打包方式. 声明渠道方式一: ...
- 作业08之《MVC实现用户权限》
1. 赋给用户一个userid,在用户角色表将用户和角色关联起来,在角色权限表中将角色和权限对应起来,权限表中存储的是左边菜单栏的名称. 2. 在判断权限时,通过用户的userid,获取其角色id,然 ...
- Typeclassopedia 阅读笔记:导言与 Functor
Typeclassopedia 阅读笔记 本文是对介绍 Haskell 中类型类(type classes)的文档 Typeclassopedia 的阅读笔记和简短总结,包含此文档中重要的知识点.读者 ...
- h5调用app中写好的的方法
做h5页面的时候,总会遇到些不能解决的问题于是就要与app做一些交互, app那边编辑好的方法后我们怎么用js语法去调用app编写好的方法 if(this.$winInfo.shebei == 1){ ...
- namespace、struct、enum、union、string(day01)
一 C++概述 C++历史背景 )C++的江湖地位 jave C C++ C# python )C++之父:Bjarne Stroustrup(--) ,Cpre,为C语言增加类的机制 ,Bjarne ...
- UOJ #310 黎明前的巧克力 (FWT)
题目传送门 题目大意:给你一个序列,定义一个子序列的权值表示子序列中元素的异或和,现在让你选出两个互不相交的子序列,求选出的这两个子序列权值相等的方案数,$n,a_{i}\leq 10^{6}$ 这是 ...