[ 题解 ] [ 最长递增子序列 ? / 贪心 ! ] HDU 1257 - 最少拦截系统

VJudge题目https://cn.vjudge.net/contest/279505#problem/H

HDU 1257 - 最少拦截系统http://acm.hdu.edu.cn/showproblem.php?pid=1257


题意:输入N,在同一行 !依次! 提供N个数字,表示 !依次! 来袭的导弹的高度。

一个导弹拦截系统一开始能拦截30000高度的导弹,之后就不能拦截高度更大的导弹。

比如说,当233233666三个导弹 !依次! 来袭,当一个拦截系统拦截233之后就只能拦截第二个233,不能拦截更高的666;只能启用第二套拦截系统。

为什么强调 依次 ?要是导弹能排序再来袭还需要那么多套系统,一个系统统统拦截好了。


输入:注意是多组数据,需要scanf()!=EOF来判断文件是否结束。


示例: 

Input 

8 389 207 155 300 299 170 158 65 

Output

2

 

我不明白这题为什么归入dp动态规划专题;这明明是贪心啊。


什么叫贪心?这道题绝对是个好栗子,贪心的典栗。先明白什么是贪心,可以理解动态规划的意义。


看懂题意后,假如让你来控制拦截系统,你会怎么做?

肯定是用能拦截当前导弹又最弱(拦截高度最低)的系统去拦截啊!不行再启用新系统呗。


换种说法是:

对于N个有循序的导弹,每次都选择拦截高度足够 又是 其中拦截高度最低 的一套去拦截。


也就是说:

对于N个有循序的问题,每次都选择能满足条件 又 损失最小/获利最大 的方案去解决问题。


这就是贪心算法的含义;在N个问题中对于每个子问题,总是都选择当前最有利的方法,以获得局部最优解。


为什么是局部最优解?因为这些问题是有循序的,必须解决这个问题才能获知下一个问题;


假如没有循序的话,贪心会非常吃亏。比如上面所说,导弹没有循序的话,排序好再拦截,永远只需要一套系统。


为什么贪心得不到这种更好的最优解?贪心是盲目的,不知道也不考虑以后的问题;

即使后面有对全局更有利的方法,也只会取当前最有利的一种而对全局未必最有利的方法。

所以经常说,贪心是局部最优解算法,动态规划是全局最优解算法。


所以贪心通常用来解决有序问题,相比之下解决无序问题的都是动态规划。一般都能保证最终答案是最优解。

(!很多有序问题还是得用动态规划来写的,也有无序问题用贪心的。关键还是在于 全局最优解 / 局部最优解 哪个是能符合题目要求的结果。)


到这里你应该对贪心有个大概的认识了。接下来把本题解决一下:


数组Greed[30003]存当前每套拦截系统的拦截高度。当读入一个导弹高度后,从数组第一个元素开始检查:

元素数值>=读入数值,说明能拦截,那么用读入数值给这个元素赋值,表明它被削弱了,然后退出;

没有元素的数值比它大,不能拦截,那么就地存下,表示新启用的系统的拦截高度如此。


这样可以保证,后面的数值总是>=前面的数值,而且每次都用数值最低的系统去拦截,从而控制损失最小。

 

最终看看数组中有多少个数值就可以了。

 

听说这题的解法叫最长递增子序列?可能这就是那个动态规划的解法吧;反正我用贪心搞定了。


代码如下: 

 1 #include <stdio.h>
 2 #include <string.h>
 3 
 4 int N=0;
 5 int tmp=0;
 6 int Greed[30003]={0};
 7 
 8 int main()
 9 {
10 while(scanf("%d",&N)!=EOF)
11 {
12     memset(Greed,0,sizeof(Greed));
13     
14     for(int n=1;n<=N;n++)
15     {
16         scanf("%d",&tmp);
17         for(int i=0;;i++)
18         {
19             if(Greed[i]>=tmp)
20             {
21                 Greed[i]=tmp;
22                 break;
23             }
24             else if(Greed[i]==0)
25             {
26                 Greed[i]=tmp;
27                 break;
28             }
29         }
30     }
31     
32     int i=0;
33     for(;Greed[i];i++);
34     printf("%d\n",i);
35     
36 }
37 return 0;
38 }

 

转载于:https://www.cnblogs.com/Kaidora/p/10514202.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值