蓝桥杯拦截导弹算法详解!C语言含注释(动态规划)

问题描述

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

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

输入格式

一行,为导弹依次飞来的高度

输出格式

两行,分别是最多能拦截的导弹数与要拦截所有导弹最少要配备的系统数

样例输入
389 207 155 300 299 170 158 65
样例输出
6
2

思路

  • 读入导弹依次飞来的高度,并保存在数组a[]中,同时记录导弹数量size。
  • 使用两个动态规划数组dpup[]和dpdown[]来记录递增和递减序列的长度。
  • 遍历导弹高度数组a[],对每个导弹进行动态规划计算:
    • 对每个导弹,向前遍历之前的导弹,更新递增和递减序列的长度。
    • 记录当前最长的递减序列长度sum和递增序列长度num。
  • 输出最多能拦截的导弹数sum和最少需要多少套拦截系统num。

首先,我们定义了几个全局变量,包括两个用于存储动态规划状态的数组dpupdpdown,一个用于存储输入序列的数组a,以及几个用于存储结果和临时变量的整数。

max函数是一个简单的辅助函数,用于返回两个整数中的较大者。

main函数中,我们首先通过一个无限循环从标准输入读取整数序列,直到遇到换行符为止。然后,我们使用两个嵌套的循环来计算每个位置的最长上升子序列和最长下降子序列的长度。对于每个位置i,我们检查所有在i之前的位置j,如果a[j]大于或等于a[i],那么我们就更新dpdown[i]dpdown[j]+1dpdown[i]中的较大者;否则,我们更新dpup[i]dpup[j]+1dpup[i]中的较大者。这样,当我们遍历完所有的位置后,dpup[i]dpdown[i]就分别存储了以a[i]结尾的最长上升子序列和最长下降子序列的长度。

最后,我们遍历dpupdpdown数组,找出其中的最大值,分别存储在sumnum中,这就是我们要找的最长的上升子序列和最长的下降子序列的长度。我们将这两个结果打印出来,然后程序结束。

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

// dpup 和 dpdown 是动态规划数组,用于存储中间结果
// a 是用于存储输入的数组
// size 是输入的数量
// sum 和 num 是用于存储最长上升子序列和最长下降子序列的长度
int dpup[100];
int dpdown[100];
int a[100];
int size = 0;
int sum = 0;
int num = 0;

// max 函数返回两个数中的最大值
int max(int a, int b)
{
	return a > b ? a : b;
}

// 主函数
int main()
{
	// b, c, i, j, k 是未使用的变量
	int b = 0, c = 0, i = 0, j = 0, k = 0;
	// 无限循环,直到输入结束
	for (i = 0;; i++)
	{
		// 读取一个整数并存储在 a[i] 中
		// 增加 size 的值
		// 如果读取到换行符,就跳出循环
		scanf("%d", &a[i]);
		size++;
		if (getchar() == '\n')
		{
			break;
		}
	}
	// 对于每个位置 i
	for (i = 0; i < size; i++)
	{
		// 初始化 dpup[i] 和 dpdown[i] 为 1
		dpup[i] = 1;
		dpdown[i] = 1;
		// 对于每个在 i 之前的位置 j
		for (j = 0; j < i; j++)
		{
			// 如果 a[j] 大于或等于 a[i]
			if (a[j] >= a[i])
			{
				// 更新 dpdown[i] 为 dpdown[i] 和 dpdown[j]+1 中的最大值
				dpdown[i] = max(dpdown[i], dpdown[j] + 1);
			}
			// 否则
			else
			{
				// 更新 dpup[i] 为 dpup[i] 和 dpup[j]+1 中的最大值
				dpup[i] = max(dpup[i], dpup[j] + 1);
			}
		}
		// 更新 sum 为 sum 和 dpdown[i] 中的最大值
		sum = max(sum, dpdown[i]);
		// 更新 num 为 num 和 dpup[i] 中的最大值
		num = max(num, dpup[i]);
	}
	// 打印 sum 和 num
	printf("%d\n%d", sum, num);

	return 0;
}

输出结果

在这里插入图片描述

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我嘞个乖乖鹅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值