链接:



最少拦截系统

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. yii xss模型安全

    在这篇文章里,我们将描述一个基于WEB应用下避免不合法的内容注入. 我们要在一个行为里使用htmlpurifier类,用这种行为可以加强任何模型并表明各属性我们想让它们XSS安全. 我写了以下行为: ...

  2. javascript和html中unicode编码和字符转义的详解

    1.html中的转义:在html中如果遇到转义字符(如“ ”),不管你的页面字符编码是utf-8亦或者是GB2312,都会直接打印成相应的字符:而当遇到(如:“\u8981”[此处的8981是16进制 ...

  3. unity5, assert

    assert可以实现“三步一岗五步一哨”可以说是保证代码正确性(安全编程)的最有力工具.在用c++写程序的时候assert语句总是要占整个程序的大部分篇幅. 但是转到unity c#,一开始没找到as ...

  4. Atitti.数据操作crud js sdk dataServiceV3设计说明

    Atitti.数据操作crud js sdk dataServiceV3设计说明 1. 增加数据1 1.1. 参数哦说明1 2. 查询数据1 2.1. 参数说明2 3. 更新数据2 3.1. 参数说明 ...

  5. hbase replication原理分析

    本文只是从总体流程来分析replication过程,很多细节没有提及,下一篇文章准备多分析分析细节.   replicationSource启动过程 org.apache.hadoop.hbase.r ...

  6. linux 查看可执行文件动态链接库相关信息(转)

    转自 http://blog.sina.com.cn/s/blog_67eb1f2f0100mgd8.html ldd <可执行文件名>       查看可执行文件链接了哪些  系统动态链 ...

  7. 李洪强总结KVC用法

  8. ext,exrReturn新增,修改删除等用

    package cn.edu.hbcf.common.vo; /** * Ext Ajax 返回对象 * * @author * @date 2012-02-21 19:30:00 * */ publ ...

  9. extjs,ComboReturn

    package cn.edu.hbcf.common.vo; import java.io.Serializable; public class ComboReturn implements Seri ...

  10. 兴奋、强类型版的PHP语言 - Hack

    Hack 是 Facebook 推出的一款新的编程语言. Hack 是由Facebook开发的,同时结合了动态类型语言(如C语言)和静态类型语言(如PHP语言)两种特点的一种编程语言.通常在使用静态类 ...