动态规划进阶:1260:【例9.4】拦截导弹

话说上一篇我们已经讲到了动态规划,那么我们今天就来继续讲一下动态规划的题目。

这次当然还是一本通上的题目了。

这个是1999年Noip的原题,也是另一道拦截导弹的进阶。

【题目描述】

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

输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,导弹数不超过1000),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

【输入】

输入导弹依次飞来的高度。

【输出】

第一行:最多能拦截的导弹数;

第二行:要拦截所有导弹最少要配备的系统数。

【输入样例】

389 207 155 300 299 170 158 65

【输出样例】

6
2

题目分析:

这一道题分两个问,一个是最多的拦截数(动态规划),另一个就是贪心。

值得注意的是,这道题没有说明要输入多少个导弹,所以我们选择另一种输入方式:

while(cin>>n)

接着呢,我们先来解决动态规划。首先将dp数组的每一个初始化为1。接着,我们用双层循环遍历dp数组。而状态转移方程也就有了:

dp[i]=max(dp[j]+1,dp[i]);

当然,我们最后还要求dp数组中的最大值。

 maxn=max(maxx,dp[i]);

到了这里,动态规划部分就写完了,先把从输入到动态规划的代码放上来:

#include <bits/stdc++.h>
using namespace std;
int a[100001];
int v[100001];
int n=1;
int ans=0;
int dp[100001]; 
int main()
{
	while(cin>>a[n]) n++;
    n--;
	int maxn=-114514;
    for(int i=1;i<=n;i++)
    {
        dp[i]=1;
        for(int j=1;j<i;j++)
            if(a[j]>=a[i])
            	dp[i]=max(dp[j]+1,dp[i]);
        maxn=max(maxn,dp[i]);
    }
    cout<<maxn<<endl;
}

接着就是贪心了。贪心的话之前应该没讲过,所以这部分详细点(bushi)。首先,我们要找到我们的贪心策略。首先先开一个系统,如果可以拦截且没有被拦截,那么拦截数量+1,标记为已经拦截。同时也要变化高度。在这道题中,这部分的代码就是:

if(a[i]<=h and v[i]==0)
{
	cnt++;
	v[i]=1;
	h=a[i];
}

代码:

最后的最后,放上AC的代码。

(你怎么还复制,为什么不自己打!)

#include <bits/stdc++.h>
using namespace std;
int a[100001];//每一枚导弹的高度
int v[100001];//是否拦截
int n=1;//导弹数量
int ans=0;//存储最少需要多少套系统 
int cnt=0;//拦截导弹数 
int dp[100001]; 
int main()
{
	while(cin>>a[n]) n++;//输入
	n--;
	int maxn=-114514;
    for(int i=1;i<=n;i++)
    {
        dp[i]=1;//初始化为1
        for(int j=1;j<i;j++)
            if(a[j]>=a[i])//第j枚导弹的高度比第i枚大
            	dp[i]=max(dp[j]+1,dp[i]);//状态转移方程
        maxn=max(maxn,dp[i]);//求dp数组的最大值
    }
    cout<<maxx<<endl;//输出拦截的最大数量
	while(cnt<n)//拦截数量小于总数
	{
		ans++;//一套系统
		int h=114514;//系统初始高度
		for(int i=1;i<=n;++i)//遍历每一枚导弹,看看哪些可以拦截
			if(a[i]<=h and v[i]==0)//可以拦截及没有被拦截
			{
				cnt++;//拦截的数量
				v[i]=1;//标记为已拦截
				h=a[i];//高度下降
			}
	} 
	cout<<ans<<endl;//输出需要几个系统
 return 0;//一万年一见的return 0
}

最后就是喜闻乐见的骗赞环节了,点赞>15马上加更!!!!!!!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值