题意:有一些穷国和一些富国分别排在两条直线上,每个穷国和一个富国之间可以建道路,但是路不能交叉,给出每个穷国和富国的联系,求最多能建多少条路

我一开始在想有点像二分图匹配orz,很快就发现,当我把穷国按顺序排了之后,富国写在它旁边,能够连接的富国就成了一个上升子序列,那么问题来了!上升子序列最长有多长?

想到了这个之后,代码就码起来吧,最开始我的做法是最土的那种,用 dp[i] 表示以 i 结尾的最长上升子序列的长度,每次对于一个 i 遍历 i 前面的所有数 j ,取小于 i 的所有 j 的最大 dp[j] ,在这个基础上加一就是以 i 结尾的最长上升子序列的长度了。

于是,就这么水过了此文终结```怎么可能!显然我TLE了!我考虑了各种简化循环的姿势,比如把循环放进读取里面啊这类的```然后```我以不同的姿势连T了三次T得不要不要的。

看了题解```dp+二分优化```你们可懂我的心情如同万千草泥马奔过```我左思右想我的程序怎么加入二分法,可是明显并不能,仔细看题解之后才发现并不是我这么求的LIS。

这里的 dp 记录的是长度为 i 的上升子序列的最优结尾情况,也就是记录长度为 i 的上升子序列的结尾最短可以是多少。

模拟一下这个 dp 的方式:

例如我们现在有一个序列  10 1 3 2 4 7 9 5 6 8

首先起始是第一个数 10 ,那么我首先记录 dp[1]=10 ,这表示我当前状态下长度为 1 的子序列最小的结尾是 10 ,这个子序列就是 10;

接下来我遍历到第二个数 1 ,1 明显是小于 dp[1] 也就是 10 的,那么我就用 1 更新 dp[1] ,dp[1]=1 ,这表示遍历到第二个数 1 时,长度为 1 的子序列最小结尾是 1,这个子序列就是 1;

然后我遍历第三个数 3 ,3 大于 dp[1] 也就是 3 大于 1,那么我就记录 dp[2]=3 ,这表示此时长度为 2 的子序列最小结尾是 3,而这个子序列就是 1 3;

第四个数 2, 2 小于 dp[2] ,那我就在前面的值里找第一个比 2 大的值将它替代,dp[1]=1<2 ,dp[2]=3>2 ,于是我用 2 更新 dp[2]=2 ;表示此时长度为 2 的上升子序列最小结尾是 2 ,这个子序列就是 1 2;

第五个数 4 , 4 大于 dp[2] ,那么我就记录 dp[3]=4 ,表示长度 3 的子序列最小结尾是 4 ,这个子序列是 1 2 4;

第六个数 7 , 7 大于 dp[3] ,记录 dp[4]=7 ,代表子序列 1 2 4 7;

第七个数 9 , 9 大于 dp[4] ,记录 dp[5]=9 ,代表子序列 1 2 4 7 9;

第八个数 5 , 5 小于 dp[5] , 那么在 dp 数组中找第一个比 5 大的数优化它,寻找到了 dp[4]=7 ,那么就改为 dp[4]=5 ,代表此时长度为 4 的子序列最小结尾为 5 ,即子序列 1 2 4 5 ;

第九个数 6 , 6 小于 dp[5] ,那么在 dp 数组中找第一个比 6 大的数优化它,寻找到了 dp[5]=9 ,那么改为 dp[5]=6 ;代表此时长度为 5 的子序列最小结尾为 6 ,1 2 4 5 6;

最后一个数 8 , 8 大于 dp{5] ,那么直接记录 dp[6]=8 ,代表子序列 1 2 4 5 6 8;

这样整个最长上升子序列就出现了 1 2 4 5 6 8 ,长度为 6 ,在这种算法中,当数列非常长的时候,在前面所有的 dp 数组中寻找首个比当前数大的数的位置就非常耗时,因此即使仅仅 dp 是会 TLE 的,由于 dp 数组无论怎么更新都是保证上升的,因此我们就可以将寻找的工作加入二分查找的思想,这样就能保证数据大的情况下不会超时了。

恩```基本就是这样,但是我显然在 T 了三次之后又 WA 了几次,坑爹的事实粗线了,大概没有人会像我这么蠢得以为它给的时候穷国的顺序一定是从 1 开始一直上升的所以根本就不用读第一个数只要读它对应的富国就好了吧```我已经感受到了世界对我深深的恶意```代码里那绿绿的一段就是我当初觉得一定是按顺序的就可以把 dp 过程直接放入读数据循环来减少循环了```

 #include<stdio.h>
#include<string.h>
int g[],dp[];
int main(){
int n;
int ti=;
while(scanf("%d",&n)!=EOF){
memset(g,,sizeof(g));
memset(dp,,sizeof(dp));
int ans=;
for(int p=;p<=n;p++){
int t,l;
scanf("%d%d",&t,&l);
g[t]=l;
}
dp[++ans]=g[];
for(int i=;i<=n;i++){
int low,high,mid;
low=;high=ans;
while(low<=high){
mid=(low+high)/;
if(dp[mid]<g[i])low=mid+;
else high=mid-;
}
dp[low]=g[i];
if(low>ans)ans++;
}
printf("Case %d:\n",++ti);
if(ans==) printf("My king, at most 1 road can be built.\n");
else printf("My king, at most %d roads can be built.\n",ans);
printf("\n");
}
return ;
}

hdu1025 dp(最长上升子序列LIS)的更多相关文章

  1. 动态规划(DP),最长递增子序列(LIS)

    题目链接:http://poj.org/problem?id=2533 解题报告: 状态转移方程: dp[i]表示以a[i]为结尾的LIS长度 状态转移方程: dp[0]=1; dp[i]=max(d ...

  2. DP——最长上升子序列(LIS)

    DP——最长上升子序列(LIS) 基本定义: 一个序列中最长的单调递增的子序列,字符子序列指的是字符串中不一定连续但先后顺序一致的n个字符,即可以去掉字符串中的部分字符,但不可改变其前后顺序. LIS ...

  3. 1. 线性DP 300. 最长上升子序列 (LIS)

    最经典单串: 300. 最长上升子序列 (LIS) https://leetcode-cn.com/problems/longest-increasing-subsequence/submission ...

  4. 最长上升子序列LIS(51nod1134)

    1134 最长递增子序列 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出长度为N的数组,找出这个数组的最长递增子序列.(递增子序列是指,子序列的元素是递 ...

  5. 【部分转载】:【lower_bound、upperbound讲解、二分查找、最长上升子序列(LIS)、最长下降子序列模版】

    二分 lower_bound lower_bound()在一个区间内进行二分查找,返回第一个大于等于目标值的位置(地址) upper_bound upper_bound()与lower_bound() ...

  6. 最长回文子序列LCS,最长递增子序列LIS及相互联系

    最长公共子序列LCS Lintcode 77. 最长公共子序列 LCS问题是求两个字符串的最长公共子序列 \[ dp[i][j] = \left\{\begin{matrix} & max(d ...

  7. 2.16 最长递增子序列 LIS

    [本文链接] http://www.cnblogs.com/hellogiser/p/dp-of-LIS.html [分析] 思路一:设序列为A,对序列进行排序后得到B,那么A的最长递增子序列LIS就 ...

  8. hdu 1025 dp 最长上升子序列

    //Accepted 4372 KB 140 ms //dp 最长上升子序列 nlogn #include <cstdio> #include <cstring> #inclu ...

  9. 题解 最长上升子序列 LIS

    最长上升子序列 LIS Description 给出一个 1 ∼ n (n ≤ 10^5) 的排列 P 求其最长上升子序列长度 Input 第一行一个正整数n,表示序列中整数个数: 第二行是空格隔开的 ...

  10. 一个数组求其最长递增子序列(LIS)

    一个数组求其最长递增子序列(LIS) 例如数组{3, 1, 4, 2, 3, 9, 4, 6}的LIS是{1, 2, 3, 4, 6},长度为5,假设数组长度为N,求数组的LIS的长度, 需要一个额外 ...

随机推荐

  1. vs 折叠跟展开所有方法。

    Ctrl + M + O: 折叠所有方法 Ctrl + M + M: 折叠或者展开当前方法 Ctrl + M + L: 展开所有方法

  2. IBInspectable / IBDesignable

    无论陈词滥调多少次,比起一个需要我们记住并且输入什么的界面来说,如果替换成我们能够看见并可控制的界面的话将会是巨大的进步. Xcode 6 提供了这样一个替代,在旧技术上建立新的互动.在设计项目的时候 ...

  3. java基础之 溢出

    堆溢出 堆(Heap)是Java存放对象实例的地方. 堆溢出可以分为以下两种情况,这两种情况都会抛出OutOfMemoryError:java heap space异常: 1.内存泄漏 内存泄漏是指对 ...

  4. GPT分区基础知识及如何在GPT分区上安装WIN7

    大硬盘和WIN8系统,让我们从传统的BIOS+MBR模式升级到UEFI+GPT模式,现在购买的主流电脑,都是预装WIN8系统,为了更好的支持2TB硬盘,更快速的启动win8,预装系统都采取了GPT分区 ...

  5. Android的R.java文件

    1.Android资源管理简介: Android应用程序资源可以分为两大类,分别放在assets和res文件夹下.assets目录下保存的是一些原始的文件,可以以任何方式来进行组织.这些文件最终会被原 ...

  6. Linux内核-链表

    linux内核链表的定义(定义了双向链表,不含数据域) 定义在 /linux-source-3.13.0/include/linux/types.h 头文件中. struct list_head { ...

  7. 使用JsonObject解析json

    第一种: [ { "0": "1", "1": "一", "id": "1", ...

  8. Java基础毕向东day05 对象与对象的区别,匿名内部类,函数的执行流程。

    1.Car c = new Car(); Car c2 = new Car(); 1> c 和 c2之间的区别? public static void main(String[] args) { ...

  9. BroadcastReceiver的最简单用法

    android系统下的广播: 电池电量低.电池充电完成.短信到来了.程序安装卸载.sd卡卸载安装 等 BrocastReceiverDemo.java public class BrocastRece ...

  10. Ubuntu 14.10 下开机不进入图形化界面

    因为装的是Ubuntu 桌面版,很占资源,所以启动时候不进入图形化界面,肯定会省不少内存 进入  /etc/X11/default-display-manager  sudo nano/etc/X11 ...