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

现假定题中所给的是 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. ATR102E Stop. Otherwise... [容斥]

    第一道容斥 \(ans[i] = \sum_{j = 0}^{min(cnt, n / 2)} (-1)^j \tbinom{cnt}{j} \tbinom{n - 2*j + k - 1}{k - ...

  2. android 异常信息The specified child already has a parent. You must call removeView() on the child's parent first. 的处理方法

    [Android异常信息]: The specified child already has a parent. You must call removeView() on the child's p ...

  3. 计算机网络实验八实验报告——应用Packet Tracer 5.0模拟器工具对WLAN进行配置

    计算机网络实验八实验报告 一.实验目的 1.熟练使用Packet Tracer 5.0模拟器: 2.应用Packet Tracer 5.0模拟器工具对WLAN进行配置. 二.实验环境 一台PC机. 模 ...

  4. bzoj4481非诚勿扰(期望dp)

    有n个女性和n个男性.每个女性的如意郎君列表都是所有男性的一个子集,并且可能为空.如果列表非空,她们会在其中选择一个男性作为自己最终接受的对象.将“如意郎君列表”中的男性按照编号从小到大的顺序呈现给她 ...

  5. 对于rqy今天讲座的一些理解和看法吧

    其实我本来以为今天晚上要学高数的,但是听到任大佬要来讲课,我自然是很开心. 其实真正接触到他和照片给我的感觉完全不一样,rqy是一个非常单一的,没有在意其他过多的事情的人,包括从他的讲座来看,大佬把自 ...

  6. hdu 3790 最短路问题 (spfa练手)

    Problem Description 给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的.   Inp ...

  7. twitter api

    1,twurl安装 1.1,安装软件管理包工具,在管理员身份打开的cmd中执行: @"%SystemRoot%\System32\WindowsPowerShell\v1.0\powersh ...

  8. 【POJ2230】Watchcow

    题目大意:给定一个 N 个点,M 条边的无向图,要求不重复地经过每条边两次,并且从 1 号节点出发最后回到 1 号节点,求一条路径. 题解:不重复地经过两次这个操作很容易地通过无向图的建边方式来实现, ...

  9. Django(十五)Form组件

    参考博客: https://www.cnblogs.com/haiyan123/p/7778888.html http://www.cnblogs.com/wupeiqi/articles/61441 ...

  10. Nginx.conf配置文件参数说明与优化

    参考连接:nginx 核心配置优化详解 先说下优化 1.nginx运行工作进程个数 worker_processes  1; Nginx进程,一般设置为和cpu核数一样(nginx启动后有多少个wor ...