链接:



最少拦截系统

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 12863    Accepted Submission(s): 5100

Problem Description
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹.

怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少套拦截系统.
 
Input
输入若干组数据.每组数据包括:导弹总个数(正整数),导弹依此飞来的高度(雷达给出的高度数据是不大于30000的正整数,用空格分隔)
 
Output
对应每组数据输出拦截所有导弹最少要配备多少套这种导弹拦截系统.
 
Sample Input
8 389 207 155 300 299 170 158 65
 
Sample Output
2
 
Source
 
Recommend
JGShining
 



算法:贪心 || Dp 【本质一样】


思路:

算是很简单的一道题目了,但是从这里 学会了所谓的 LIS 优化,所以想好好总结下了

开始是用贪心做的了,复杂度 O(n^2)最容易理解的一种写法了。
后来看了下这篇博客的分析:说是用“最长上升子序列的长度”http://www.cnblogs.com/dgsrz/articles/2384081.html
复杂度 O(n^2)高了点,还是比较好理解的了。

/*
最长上升子序列(一维形式DP)
opt[i]=max(opt[j])+1, opt[i]) (0<=j<i 且num[j]<=num[i]) {最长非下降序列}
opt[i]=max(opt[j])+1, opt[i]) (0<=j<i 且num[j]>num[i]) {最长下降序列}
该算法复杂度为O(n^2)
*/

但是这样就还不如贪心了效率。后来又去找了下 LIS 的资料:


发现 LIS 的 O(nlogn)的算法其实和贪心的本质很像,下面就以这一题仔细总结下。


样例中的数据是:

389 207 155 300 299 170 158 65

那么采取贪心的思路:


以数组 h[] 记录拦截系统当前的拦截高度,先初始化为最大值 INF = 30000+10,
表示每一个新拦截系统都能拦截所有的导弹,然后遇到一个导弹就往前找看是否有已经使用了的系统能拦截,如果有,直接用;否则重新弄一个系统。最后再看用了几个系统就好了。

第一个导弹 389 < h[1] ( h[1] = INF)被第一个系统拦截 h[1] = 389
第二个导弹 207 < h[1] 被第一个系统拦截 h[1] = 207
第三个导弹 155 < h[1] h[1] = 155
第四个导弹 300 > h[1] , 300 < h[2] ( h[2] = INF ) 所以新开发一个系统拦截第四个导弹, h[2] = 300
第五个导弹 299 > h[1] , 299 < h[2] 被第二个系统拦截 h[2] = 299
第六个导弹 170 > h[1] , 170 < h[2] h[2] = 170
第七个导弹 158 > h[1] , 158 < h[2] h[2] = 158
第八个导弹 65 < h[1] 被第一个系统拦截 h[1] = 65

所以最后使用了两个系统就拦截了所有的导弹【遍历 h[]数组从 1到 n 看有几个 != INF 就说明使用了】

导弹高度:389
207 155 300 299 170 158 65
使用的拦截系统: 1 1 1 2 2 2 2 1


下面说一下DP的 O(n^n)的思路:


dp[i] 记录的是拦截第 i 个导弹的系统的编号 index
先初始化所有的导弹都被第一个系统拦截。dp[i] = 1

dp[i] = max(dp[i], dp[j]+1) 【0<=j<i && high[i] > high[j]】
当遇到第 i 个导弹的时候,看前面已经拦截了的导弹的系统是否能够拦截第 i 个导弹 0 <= j < i
一旦第 i 个导弹比第 j 个导弹要高,那么依照上面贪心的思路,拦截第 i 个导弹的系统必定比拦截第 j 个导弹的系统大,
最少大一个【如果 (j < k < i) 如果第 k 个导弹没有比第 i 个低的】
(不知道说清楚了没有,反正我是这么理解的了)
那么最后出的 dp[]对应的值将是上面贪心的思想的 h[]的下标

导弹高度 a[]:389 207 155 300 299 170 158 65
使用的拦截系统 dp[]: 1 1 1 2 2 2 2 1

最后输出最大的 dp[] 就是所需系统的个数了

最后总结下 Dp 的 O (nlogn)的思路:


其实本质上都一样了,就像这篇神奇的 LIS 的优化,奇怪的命名方式,看了我大半天才懂

首先第一轮遍历所有的导弹,是不能改了的这里消耗 O(n)
然后就是把第二重循环改成了二分而已 ,二分复杂度 O(logn)

首先我们要明确的是上面 Dp O(n^2) LIS 思想的第二轮找的是什么?

首先还是先定义一个 h[] 数组存储拦截系统的高度,那么根据前面贪心的分析:
我们可以明确这一点只要是用过了的系统 h[] 那么它一定是单调递增
这个时候 h[] 保存的就是遍历到第 i 个导弹的时候,当前使用过的系统目前能够拦截导弹的最高值

所以第二轮找的是前面第一个 h[index] >= a[i] ,然后再更新 h[index]= a[i]
永远维护 h[]是单调递增的,最后输出 h[]的使用长度,或是像上面贪心一样遍历一遍数出用了几个 h[] 都可以

那么再回到我们的关键问题:如何使得第二轮的顺序查找 O(n) 优化成 O(logn)
注意到:h[]永远是单调递增的,那么直接写个二分查找就可以了。基本上对于这题可以 0 ms 秒过,
最终发现这样也是网上传的 LIS 的最优的解法
如果你想偷懒:那么二分也不用写了,直接加个 algorithm 的头文件了,调用 upper_bound就好了【kuangbin大神教的Orz】
int index = upper_bound(h,h+len+1,a[i])-h; //保证 h[index] 是数组 h 中第一个 >= a[i] 的

下面依次贴代码,看不懂的输出中间变量就好了。


code:


贪心:


D Accepted 236 KB 15 ms C++ 746 B


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std; const int maxn = 1000+10;
const int INF = 30000+10; //导弹高度不会超过 30000
int a[maxn]; //存导弹的高度
int h[maxn]; // h[i] 表示第 i 个导弹系统拦截的最低高度 int main()
{
int n;
while(scanf("%d", &n) != EOF)
{
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
h[i] = INF; //初始化保证每一个拦截系统都能拦截所有的导弹
} for(int i = 0; i < n; i++)
{
for(int j = 0; j <= i; j++) //往前找开发了的导弹系统,看是否能拦截当前导弹, 最坏的结果是每个导弹都需要一个新的导弹系统来拦截,所以遍历到 i
{
if(h[j] >= a[i]) //一旦找到符合条件的拦截系统
{
h[j] = a[i]; // 第 j 个拦截系统拦截了第 i 个导弹 , 更新它的目前可以拦截的导弹的高度
break; //第 i 个导弹已经拦截,跳出里面那层循环
}
} } int tot = 0;
for(int i = 0; i < n; i++) //计算总共用了几个导弹系统
if(h[i] != INF) //如果第 i 个导弹系统的高度不等于初始值说明它用过
tot++;
printf("%d\n", tot);
}
return 0;
}



DP之 O(n^n)


D Accepted 236 KB 15 ms C++ 792 B


/*****************************************************
dp[i] = max(dp[i], dp[j]+1) 【0<=j<i, a[i] > a[j]】
如果当前导弹 i 的高度 > 前面的导弹 j 的高度,
那么拦截当前导弹 i 的系统,一定是拦截 j 的后面的系统
******************************************************/
#include<stdio.h>
#include<algorithm>
using namespace std; const int maxn = 1000+10;
const int INF = 30000+10; int a[maxn]; //存导弹的高度
int dp[maxn]; //d[i] 表示第 i 个导弹是被第 dp[i] 个拦截系统拦截的 int main()
{
int n;
while(scanf("%d", &n) != EOF)
{
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
dp[i] = 1;
} for(int i = 0; i < n; i++)
{
for(int j = 0; j < i; j++)
if(a[i] > a[j])
dp[i] = max(dp[i], dp[j]+1);
} int ans = 0;
for(int i = 0; i < n; i++)
ans = max(ans, dp[i]);
printf("%d\n", ans);
}
return 0;
}





Dp之 O(nlogn) 二分查找:


D Accepted 236 KB 0 ms C++ 959 B


#include<stdio.h>
#include<algorithm>
using namespace std; const int maxn = 1000+10; int a[maxn]; //导弹高度
int h[maxn]; // h[i] 表示第 i 个系统目前拦截的高度 int find(int h[], int len, int ha) //返回 index , 数组h[] 中, 第一个h[index] >= ha
{
int left = 0;
int right = len; while(left <= right)
{
int mid = (left+right) / 2; if(ha > h[mid]) left = mid+1;
else if(ha < h[mid]) right = mid-1;
else return mid;
}
return left;
} int main()
{
int n;
while(scanf("%d", &n) != EOF)
{
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
} h[0] = -1;
h[1] = a[0];
int len = 1; for(int i = 1; i < n; i++)
{
int index = find(h,len, a[i]);
h[index] = a[i];
//printf("test : h[%d] = %d\n", index, h[index]);
if(index > len)
len = index;
}
printf("%d\n", len);
}
return 0;
}

Dp O (nlogn)之直接调用upper查找


D Accepted 236 KB 0 ms C++ 814 B 2013-08-05 11:34:41

#include<stdio.h>
#include<algorithm>
using namespace std; const int maxn = 1000+10;
const int INF = 30000+10;
int a[maxn]; //导弹高度
int h[maxn]; // h[i] 表示当前第 i 个系统拦截的高度 int main()
{
int n;
while(scanf("%d", &n) != EOF)
{
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
// h[i] = INF;
} h[0] = -1;
h[1] = a[0];
int len = 1; for(int i = 1; i < n; i++)
{
int index = upper_bound(h,h+len+1,a[i])-h; //保证 h[index] 是数组 h 中第一个 >= a[i] 的
h[index] = a[i];
//printf("test: h[%d] = %d\n", index, h[index]);
if(index > len)
len = index;
}
//for(int i = 0; i <= n; i++) printf("%d ", h[i]); printf("\n");
printf("%d\n", len);
}
return 0;
}






hdu 1257 最少拦截系统【贪心 || DP——LIS】的更多相关文章

  1. HDU 1257 最少拦截系统(dp)

    Problem Description 某国为了防御敌国的导弹突击,发展出一种导弹拦截系统.可是这样的导弹拦截系统有一个缺陷:尽管它的第一发炮弹可以到达随意的高度,可是以后每一发炮弹都不能超过前一发的 ...

  2. hdu 1257 最少拦截系统(贪心)

    解题思路:[要充分理解题意,不可断章取义] 贪心:每个防御系统要发挥其最大性能, 举例: Input : 9 389 207 155 300 299 170 155 158 65 Output: 2 ...

  3. HDU 1257 最少拦截系统 最长递增子序列

    HDU 1257 最少拦截系统 最长递增子序列 题意 这个题的意思是说给你\(n\)个数,让你找到他最长的并且递增的子序列\((LIS)\).这里和最长公共子序列一样\((LCS)\)一样,子序列只要 ...

  4. HDOJ 1257 最少拦截系统 【DP】

    HDOJ 1257 最少拦截系统 [DP] Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...

  5. HDU 1257 最少拦截系统(贪心 or LIS)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1257 最少拦截系统 Time Limit: 2000/1000 MS (Java/Others)   ...

  6. HDU 1257最少拦截系统[动态规划]

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1257                                                 最 ...

  7. POJ - 2533 Longest Ordered Subsequence与HDU - 1257 最少拦截系统 DP+贪心(最长上升子序列及最少序列个数)(LIS)

    Longest Ordered Subsequence A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let ...

  8. HDU 1257 最少拦截系统 (DP || 贪心)

    最少拦截系统 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Statu ...

  9. HDU 1257——最少拦截系统——————【LIS变型题】

    最少拦截系统 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Statu ...

随机推荐

  1. spring in action第一章小结1

    1 spring基本理念是简化java开发. 使用以下4个策略简化java开发 1) 基于POJO的轻量级和最小侵入性编程 2)通过使用DI和AOP实现松耦合 3)基于切面和惯例进行声明式编程 4)通 ...

  2. composer自动加载一个文件后必须执行命令composer dump-autoload

    "autoload": { "classmap": [ "database" ], "psr-4": { "A ...

  3. TypeScript 入门指南

    你是否听过 TypeScript? TypeScript 是微软开发的 JavaScript 的超集,TypeScript兼容JavaScript,可以载入JavaScript代码然后运行.TypeS ...

  4. Android--&gt;Realm(数据库ORM)使用体验,lambda表达式

    Realm,为移动设备而生.替代 SQLite 和 Core Data. 非常庆幸,官方帮助文档有中文: https://realm.io/cn/docs/java/latest/ 尽管眼下最新的版本 ...

  5. Spark-shell 无法启动之网络问题

    由于需要首次手动安装sbt,需要联网,故将虚拟机的网络适配器模式设置为"桥接模式",这样就可以和互联网相连接. 但是后面执行"spark-shell  --master ...

  6. 修复Win10下Synaptics触摸板双指触击无法打开右键菜单的问题

    从Win8.1开始,Synaptics触摸板驱动的键值就不能正确设置,使得双指触击失效,无法打开右键菜单. 解决方法1.打开注册表:2.搜索“2FingerTapAction”,或直接定位到以下两个路 ...

  7. 一种480 MHz无线数传模块的设计

    一种480 MHz无线数传模块的设计 来源:电子技术应用2012年第6期 作者:严 冬,黄 聃,王 平,彭 杰,朱柏寒2012/8/13 16:56:32 关键词: 微处理器|微控制器 物联网 RF  ...

  8. MySQL集群系列1:2台机器搭建双主集群

    先配置静态IP 2台机器mysql密码一样,最好在同一局域网内,最好在mysql刚安装时就配置好,后面有数据了不好同步. 本文实现了2台机器mysql数据同步成功: 配置my.cnf 先关闭防火墙 s ...

  9. json中的日期格式转换(扩展new date()显示格式)

    在java  spring mvc 开发过程中,通过json 格式,向前端传递数据,日期格式发生了转变, 在前台数据展示时,要进行一定格式的转换才能正常显示: 我在开发中使用了easy ui 和my ...

  10. RGB565 转换 BMP24

    今晚有心情,就做完了BMP16(RGB565) 转换成BMP24 的小程序.其中最关键的地方是: // k,WORD类型,是RGB565 的一个点的数据(可以认为是灰度). r=(k & 0x ...