题意是要在两条平行线间连点,要在线不交叉的前提下尽可能多的连线,问最多能连多少条线。

现假定题中所给的是 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(最长上升子序列)的更多相关文章

  1. hdu 1950 最长上升子序列(lis) nlogn算法【dp】

    这个博客说的已经很好了.http://blog.csdn.net/shuangde800/article/details/7474903 简单记录一下自己学的: 问题就是求一个数列最长上升子序列的长度 ...

  2. HDU 5773 最长上升子序列

    题意 给出一个序列 问它的最长严格上升子序列多长 这个序列中的0可以被替代为任何数 n的范围给出了1e5 所以平常的O(n*n)lis不能用了 在kuangbin的模板里有O(nlogn)的模板 套上 ...

  3. hdu 1950 最长上升子序列

    //Accepted 3540 KB 62 ms //dp 最长上升子序列 #include <cstdio> #include <cstring> #include < ...

  4. HDU 5748 最长上升子序列的长度nlogn(固定尾部)

    Bellovin Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total ...

  5. HDU 1159 最长公共子序列(n*m)

    Common Subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  6. HDU 1159 最长公共子序列

    Common Subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  7. hdu 5773 最长递增子序列 (nlogn)+贪心

    The All-purpose Zero Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Oth ...

  8. HDU - 1503 最长公共子序列记录路径

    题意:先给两个水果的名字然后得出一个最短的序列包含这两个词. 思路:我一开始的思路是先求出最长公共子序列,然后做一些处理将其他的部分输出来:两种水果的字符串和最长公共子序列的字符串这三个字符串做对比, ...

  9. HDU - 1160 最长上升子序列以及记录路径

    题意:第一列,给出老鼠的重量,第二列,给出老鼠的速度,要证明老鼠的重量越大,速度越小,给出最多老鼠的数量,并说明第几只. 思路:先将老鼠按照重量从大到小排序,然后速度是从小到大,求最长上升子序列,学习 ...

随机推荐

  1. 【vijos1780】【NOIP2012】开车旅行 倍增

    题目描述 有\(n\)个城市,第\(i\)个城市的海拔为\(h_i\)且这\(n\)个城市的海拔互不相同.编号比较大的城市在东边.两个城市\(i,j\)之间的距离为\(|h_i-h_j|\) 小A和小 ...

  2. 卢卡斯定理&扩展卢卡斯定理

    卢卡斯定理 求\(C_m^n~mod~p\) 设\(m={a_0}^{p_0}+{a_1}^{p_1}+\cdots+{a_k}^{p_k},n={b_0}^{p_0}+{b_1}^{p_1}+\cd ...

  3. HNOI2019 退役记

    窗外风雨大作. 凌晨两点又被噩梦惊醒,朦胧中看见书桌的灯还亮着. 走近书桌,有一个人正在敲打着键盘,屏幕上是一些似曾相识的东西. 被水浸湿的头发随意地搭在额头上,鼻梁上架着一副眼镜,镜片上全是小水珠, ...

  4. android 通过修改图片像素实现CircleImageView

    CircleImageView实现方法有很多种,各有优缺点,因此需要按照不同的场景使用.我们今天使用修改图片像素的方法实现CircleImageView,主要知识点无非是勾股定理和点到圆形的距离. 素 ...

  5. 自学zabbix集锦

    zabbix概念集锦 01 Zabbix采集数据方式 02 开源监控软件Cacti.nagios 03 Zabbix常用的术语 04 Zabbix核心概念回顾 05 Zabbix triggers-- ...

  6. Spring注解方式实现任务调度

    原文:http://docs.spring.io/spring/docs/4.0.1.BUILD-SNAPSHOT/javadoc-api/ 注解类型:EnableScheduling @Target ...

  7. js jquery 遍历 for,while,each,map,grep

    js jquery 遍历 一,for循环. // 第一种var arr = [1, 2, 3];for(var i = 0; i < arr.length; i++) { console.log ...

  8. WIndows下将文件夹映射为磁盘

    subst 盘符 文件夹路径 [/d] 映射 将e:\work映射为z:盘,使用subst z: e:\work 取消映射 取消z盘映射,使用subst z: /d 参考资料:http://mp.we ...

  9. A1144. The Missing Number

    Given N integers, you are supposed to find the smallest positive integer that is NOT in the given li ...

  10. Java 数组+循环升级篇

    数组是一个变量,存储相同数据类型的一组数据(就是能存储很多数值的数据类型) 如果说声明一个变量就是在内存空间划出一块合适的空间,那么声明一个数组就是在内存空间划出一串连续的空间. 数组的基本要求 标识 ...