HDU 1025(最长上升子序列)
题意是要在两条平行线间连点,要在线不交叉的前提下尽可能多的连线,问最多能连多少条线。
现假定题中所给的是 9 组点,分别是:1—3,2—8,3—5,4—9,5—2,6—4,7—6,8—7,9—1,如图示:
则将所给的每组 p 和 r 存在数组 a[ ] 中:a[ p ] = r;
问题就转化成了在数组 a[ ] 中求最长上升子序列的长度。显然要是直接暴力做的话,每个数字都有选和不选两种可能,那么就是 O( 2 ^ n ) 的复杂度,这是无法接受的。
除暴力外求解最长上升子序列长度的方法有三种(仅本人了解到的):
一、直接用数组去记录选择到该数的最长上升子序列长度,每次从前往后扫一遍,若扫到的数字比所求解位置的数字小,且到该数字的最长上升子序列长度 +1大于已有的到该数字的最长上
升子序列长度,则更新到该数字的最长上升子序列长度,求出这些长度的最大值即为序列的最长上升子序列长度。
以上述 9 组点为例,要求 a[ ] = { 0,3,8,5,9,2,4, 6,7,1 } 的最长上升子序列长( 0 只是占位,与所求数据无关 ),则初始化数组 d[ ] 为 0 :
d[ 1 ] = 1;
d[ 2 ] = 2; ( a[ 2 ] > a[ 1 ] && d[ 2 ] < d[ 1 ] + 1 )
d[ 3 ] = 2; ( a[ 3 ] > a[ 1 ] && d[ 3 ] < d[ 1 ] + 1 )
d[ 4 ] = 3; ( a[ 4 ] > a[ 3 ] && d[ 4 ] < d[ 3 ] + 1 )
......
得到数组 d[ ] 的最大值为 4,则数列的最长上升子序列的长度为 4 。
代码如下:
#include <bits/stdc++.h>
using namespace std;
int n,p,r,cnt,len,a[],d[];
int main()
{
cnt = ;
while(~scanf("%d",&n))
{
memset(d,,sizeof(d));
for(int i = ; i < n; ++i)
{
scanf("%d%d",&p,&r);
a[p] = r;
}
len = d[] = ;
for(int i = ; i <= n; ++i)
for(int j = ; j < i; j++)
{
if(a[i]>a[j] && d[i]<d[j]+)
d[i] = d[j]+;
else d[i] = ;
if(len < d[i]) len = d[i];
}
printf("Case %d:\n",cnt++);
if(len==) printf("My king, at most 1 road can be built.\n\n");
else printf("My king, at most %d roads can be built.\n\n",len);
}
return ;
}
但是这种 O( n ^ 2 ) 复杂度的方法是会超时的。
二、多开一个数组存放当前已选中数的顺序,用二分的方法依次找到每一个待处理数字的位置再对所选序列进行调整,调整的方法就是将所处理数字按序插入所选序列中,用它替换比它大的下一个数,
若所选序列不存在比它大的数,则将它直接加在所选序列的最后,序列最终的长度就是数列的最大上升子序列长度。主要的思想就是在不损失已有最大升序长度的基础之上将大的数换小,
增大后续出现的数字比当前所选序列最大值更大的可能性。
继续以上述 9 组点为例,这一次的数组 a[ ] 仍然存放数列,数组 d[ ] 存放所选数列:
d[ ] = { 3 }, len = 1; (第一个数 3 直接加入所选序列)
d[ ] = { 3,8 }, len = 2; (第二个数 8 ,所选序列中没有比它大的数,直接加在最后)
d[ ] = { 3,5 }, len = 2; (第三个数 5 ,位于所选序列的 3 与 8 之间,以 5 替换 8 )
d[ ] = { 3,5,9 }, len = 3; (第四个数 9 ,所选序列中没有比它大的数,直接加在最后)
d[ ] = { 2,5,9 }, len = 3; (第五个数 2 ,位于所选序列的 3 之前,以 2 替换 3 )
d[ ] = { 2,4,9 }, len = 3; (第六个数 4 ,位于所选序列的 2 与 5 之间,以 4 替换 5 )
d[ ] = { 2,4,6 }, len = 3; (第七个数 6 ,位于所选序列的 4 与 9 之间,以 6 替换 9 )
d[ ] = { 2,4,6,7 }, len = 4; (第八个数 7 ,所选序列中没有比它大的数,直接加在最后)
d[ ] = {1,4,6,7 }, len = 4; (第九个数 1 ,位于所选序列的 2 之前,以 1 替换 2)
则数列的最长上升子序列长度为 4 。
代码如下:
#include <bits/stdc++.h>
using namespace std;
int n,len,cnt,a[],d[];
int getp(int x,int l,int r)
{
int mid;
while(l <= r)
{
mid = (l+r)>>;
if(d[mid] == x) return mid;
if(d[mid] > x) r = mid-;
else l = mid+;
}
return l;
}
int main()
{
int p,r;
cnt = ;
while(~scanf("%d",&n))
{
for(int i = ; i < n; ++i)
{
scanf("%d%d",&p,&r);
a[p] = r;
}
d[] = a[];
len = ;
for(int i = ; i <= n; ++i)
{
if(a[i]>d[len-]) d[len++] = a[i];
else d[getp(a[i],,len)] = a[i];
}
printf("Case %d:\n",cnt++);
if(len==) printf("My king, at most 1 road can be built.\n\n");
else printf("My king, at most %d roads can be built.\n\n",len);
}
return ;
}
这个做法仅 O( nlogn ) 的复杂度,主要是在找所处理数在所选序列的位置时使用了二分的方法优化得到的。
三、树状数组优化。等今晚学会了明天再写......
致谢: https://www.cnblogs.com/GodA/p/5180560.html
https://blog.csdn.net/George__Yu/article/details/75896330
https://blog.csdn.net/u011721440/article/details/21107113
非常感谢这些博客作者的贡献。
HDU 1025(最长上升子序列)的更多相关文章
- hdu 1950 最长上升子序列(lis) nlogn算法【dp】
这个博客说的已经很好了.http://blog.csdn.net/shuangde800/article/details/7474903 简单记录一下自己学的: 问题就是求一个数列最长上升子序列的长度 ...
- HDU 5773 最长上升子序列
题意 给出一个序列 问它的最长严格上升子序列多长 这个序列中的0可以被替代为任何数 n的范围给出了1e5 所以平常的O(n*n)lis不能用了 在kuangbin的模板里有O(nlogn)的模板 套上 ...
- hdu 1950 最长上升子序列
//Accepted 3540 KB 62 ms //dp 最长上升子序列 #include <cstdio> #include <cstring> #include < ...
- HDU 5748 最长上升子序列的长度nlogn(固定尾部)
Bellovin Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total ...
- HDU 1159 最长公共子序列(n*m)
Common Subsequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- HDU 1159 最长公共子序列
Common Subsequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- hdu 5773 最长递增子序列 (nlogn)+贪心
The All-purpose Zero Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Oth ...
- HDU - 1503 最长公共子序列记录路径
题意:先给两个水果的名字然后得出一个最短的序列包含这两个词. 思路:我一开始的思路是先求出最长公共子序列,然后做一些处理将其他的部分输出来:两种水果的字符串和最长公共子序列的字符串这三个字符串做对比, ...
- HDU - 1160 最长上升子序列以及记录路径
题意:第一列,给出老鼠的重量,第二列,给出老鼠的速度,要证明老鼠的重量越大,速度越小,给出最多老鼠的数量,并说明第几只. 思路:先将老鼠按照重量从大到小排序,然后速度是从小到大,求最长上升子序列,学习 ...
随机推荐
- python3 hashlib模块
hashlib是一个加密模块,可以将明文加密为密文: md5,sha加密:过程不可逆转.
- 【APIO2018】铁人两项(圆方树,动态规划)
[APIO2018]铁人两项(圆方树,动态规划) 题面 UOJ 洛谷 BZOJ 题解 嘤嘤嘤,APIO的时候把一个组合数写成阶乘了,然后这题的70多分没拿到 首先一棵树是很容易做的,随意指定起点终点就 ...
- 「九省联考 2018」IIIDX 解题报告
「九省联考 2018」IIIDX 这什么鬼题,送的55分要拿稳,实测有60? 考虑把数值从大到小摆好,每个位置\(i\)维护一个\(f_i\),表示\(i\)左边比它大的(包括自己)还有几个数可以选 ...
- noiac132 B君的第三题 (树形dp)
传送门 本来想用点分治做,结果root又求不对 算的时候还算错了 我好菜啊 结果szr大佬告诉我是树形dp 我好菜啊!! 我们有$\lceil \frac{x}{k} \rceil = \frac{x ...
- ssh整合hibernate 使用spring管理hibernate二级缓存,配置hibernate4.0以上二级缓存
ssh整合hibernate 使用spring管理hibernate二级缓存,配置hibernate4.0以上二级缓存 hibernate : Hibernate是一个持久层框架,经常访问物理数据库 ...
- 基于Jenkins,docker实现自动化部署(持续交互)
前言 随着业务的增长,需求也开始增多,每个需求的大小,开发周期,发布时间都不一致.基于微服务的系统架构,功能的叠加,对应的服务的数量也在增加,大小功能的快速迭代,更加要求部署的快速化,智能化.因此 ...
- Centos 6.5 安装和使用docker
基于本人一贯的习惯,关于“某某某是什么”这样的问题,请百度吧,会有更专业的人士,会比我说的更详细更深,这里我只给出本人亲历的安装和使用过程. 1.安装 先检查服务器环境,docker要求操作系统Cen ...
- QML学习笔记(一)-防止鼠标穿透事件
作者: 狐狸家的鱼 Github: 八至 1.防止鼠标穿透 MouseArea{ anchors.fill: parent; onClicked: {}; onReleased: {}; onPres ...
- A1002. A+B for Polynomials
This time, you are supposed to find A+B where A and B are two polynomials. Input Each input file con ...
- 收藏:H.264编码原理以及I帧B帧P帧
来源: https://www.cnblogs.com/herenzhiming/articles/5106178.html 前言 ----------------------- H264是新一代的编 ...