导弹防御系统[&&导弹拦截系统]

导弹防御系统【dfs】

题目链接
引言(请忽略):今天是小白ACM集训的日子,然后数据结构实在是太难了,真是学不动了,然后就只能无助地去复习以前的题了,记得以前在SDUT程设二里面有一道题叫最少拦截系统,它是一道贪心,我个人觉得最长上升子序列的思路跟它有些相似。我们先分析一下这道题,引入一下这道最少拦截系统的题干和代码:
最少拦截系统
Description
提炼一下题干,就是飞来一些导弹,需要用炮弹系统依次拦截,它的第一发炮弹能够到达任意的高度,但以后每一发炮弹都不能超过前一发的高度.比如如果飞来一颗比之前所有导弹都高的导弹,你只能增加一个拦截系统。求拦截系统个数
Input
输入包括:导弹总个数(正整数),导弹依此飞来的高度(雷达给出的高度数据是不大于30000的正整数,用空格分隔)

Output
对应输出拦截所有导弹最少要配备多少套这种导弹拦截系统.

Sample
Input
8 389 207 155 300 299 170 158 65
Output
2


#include <stdio.h>
#include <string.h>
int a,i;//用来保存导弹的高度 
int b[100000];//用来保存拦截系统能够拦截的高度 
int main()
{
	int n,cnt;//n代表总共的导弹的个数,cnt代表拦截系统的个数 
	while(scanf("%d",&n)!=EOF)
	{
		memset(b,0,sizeof(b));//b用来保存拦截系统能够拦截的最大高度 
		cnt=1;	
		for(i=0;i<n;i++)
		{   
			scanf("%d",&a);
			if(i==0)
			  b[0]=a;
			int j;
			for(j=0;j<cnt;j++)//每次都用较小的高度来替换b中的数值 
			{
				if(b[j]>=a)//如果拦截系统能够拦截就拦截 
				{
					b[j]=a;
					break;
				}
			}
			if(j==cnt)//如果拦截系统都不能够拦截,就只能够再重新用一个拦截系统了 
			{
				b[cnt++]=a;
			}
		}
		printf("%d\n",cnt);
	}
	return 0;
}

这道题就是一道在已有的拦截系统里查找的题,因为每一套拦截系统在导弹飞来之时会判断能否拦截,并更新每一套拦截系统可拦截的最大高度。最后把计数的cnt输出即可,是一道贪心策略的题目,感觉难度还可以。
但是今天这道题目可真是给我这个小白难坏了。

187. 导弹防御系统

描述
为了对抗附近恶意国家的威胁,R国更新了他们的导弹防御系统。

一套防御系统的导弹拦截高度要么一直 严格单调 上升要么一直 严格单调 下降

例如,一套系统先后拦截了高度为3和高度为4的两发导弹,那么接下来该系统就只能拦截高度大于4的导弹。

给定即将袭来的一系列导弹的高度,请你求出至少需要多少套防御系统,就可以将它们全部击落。

输入格式
输入包含多组测试用例。

对于每个测试用例,第一行包含整数n,表示来袭导弹数量。

第二行包含n个不同的整数,表示每个导弹的高度。

当输入测试用例n=0时,表示输入终止,且该用例无需处理。

输出格式
对于每个测试用例,输出一个占据一行的整数,表示所需的防御系统数量。

数据范围
1≤n≤50
输入样例

5
3 5 2 4 1
0 

输出样例

2

样例解释
对于给出样例,最少需要两套防御系统。

一套击落高度为3,4的导弹,另一套击落高度为5,2,1的导弹。
题解:这道题网上大佬的解析很多,我作为小白也没有什么太深入的理解,可能有些错误认识。这里仅仅记录自己的一个学习过程。
首先我们看题,可以知道,有的导弹可以上升,也有的可以下降,所以我们不能像上道题那样,仅仅去记录多少组上升子序列的问题。
我想到的就是枚举然后去暴搜;
一个导弹的高度是应该放在递增的序列还是递减的序列,然后放到哪一个递增或者递减序列之中,就是要核心讨论的问题。
这个题对时间复杂度有要求,所以在搜索的过程要时刻想办法优化,在适当的地方去剪枝。
搜索

  1. 第一种搜索可能就是BFS,宽度优先,网上有大佬用这种方法,但介于内存储存的一些写法我不太明白,就不多说了;
  2. 第二种就DFS,就是我采用的方法,因为在剪枝的过程确实很好写,我就只能想到这个方法了,然后可以采用声明全局最小值记录和迭代深搜两种思路,时间复杂度都是n*2^n,所以我就用前者来写这个代码。

因为小白也不怎么会,可能注释写的比较繁琐,代码如下:

#include <iostream>
using namespace std;
const int N = 100;
int n;
int q[N];//q:依次飞来的导弹; 
int up[N],down[N];
int ans;  // 记录全局最小变量;

void dfs(int x,int su,int sd)  // x:当前枚举到哪个数,su:上升子序列的个数,sd:下降子序列的个数
{
    if(su + sd >= ans) return ; // 剪枝---此时不可能再更新了,return
    if(x==n) // 递归结束
    {
        ans = su + sd;//上升子序列和下降子序列个数和为答案 
        return ;
    }

    // 情况1:将当前数放到上升子序列中
    int k =0;//k用来遍历当前所有上升子序列的末尾值 
    while(k < su && up[k] >= q[x]) k++;  // 因为序列下标是从0开始的,所以是<
    int t=up[k]; // 为后边回溯标记当前遍历; 
    up[k] = q[x];//如果q[u]比末尾值大,则更新up数组; 
    if(k < su) dfs(x+1,su,sd); // 如果被更新---即不用另开一个上升子序列m
	//如果k>=su说明q[当前]小于所有上升子序列 
    else dfs(x+1,su+1,sd);//则su+1 (增加一个系统),继续深搜 
    up[k] = t; // 回溯之前的状态 
   //情况2与上同理; 
    // 情况2:将当前数放到下降子序列中
    k = 0;
    while(k < sd && down[k] <= q[x]) k ++;
    t = down[k];
    down[k] = q[x];
    if(k < sd) dfs(x+1,su,sd);
    else dfs(x+1,su,sd+1);
    down[k] = t;
}
int main()
{
    while(cin >> n&& n)
    {
        for(int i=0;i<n;i++)
		  cin >> q[i];
        ans=n;
        dfs(0,0,0);
        cout<<ans<<endl;
    }

    return 0;
}

这个题我觉得对我来说是挺难的,也借鉴了许多网上大佬的思路,仅用来记录自己的学习过程吧。
新手上路,多多包涵。

  • 15
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
拦截导弹问题,也称为“拦截导弹游戏”或“拦截导弹防御系统问题”,是一个经典的动态规划问题。 问题描述: 有一座山,山上有一些导弹在不同的高度上飞行,你需要设计一套导弹拦截系统,使得拦截导弹的代价最小。 假设你可以部署一些导弹拦截器,每个拦截器能够拦截一定高度范围内的导弹。拦截器的部署代价与其拦截高度范围成正比,也就是说,拦截范围越大,部署代价越高。 你需要设计一套拦截系统,使得拦截代价最小,并能够完全拦截所有的导弹。 问题分析: 这个问题可以用动态规划来解决。我们可以定义一个状态 $f(i)$ 表示在第 $i$ 个导弹高度处放置拦截器所需的最小代价。则最终的答案就是 $f(n)$,其中 $n$ 表示导弹的数量。 接下来考虑如何求解状态转移方程。假设当前在第 $i$ 个导弹高度处放置一个拦截器,则前面所有高度小于 $i$ 的导弹都必须被拦截。因此,我们可以考虑将这些导弹按照高度从大到小排序,然后依次考虑每个导弹被拦截的情况。 对于第 $i$ 个导弹,我们需要考虑它是否被拦截。如果它被拦截,则拦截器的范围必须包括这个导弹的高度;否则,我们可以不用在这个高度处放置拦截器。因此,状态转移方程可以表示为: $$ f(i) = \begin{cases} \min\limits_{j=1}^{i-1}\{f(j) + c(i,j)\},&\text{如果第 }i\text{ 个导弹被拦截}\\ f(i-1),&\text{如果第 }i\text{ 个导弹不被拦截} \end{cases} $$ 其中 $c(i,j)$ 表示在第 $j$ 个导弹高度处放置一个拦截器,可以拦截第 $i$ 个导弹的代价。显然,$c(i,j)$ 可以通过计算高度差来计算,即 $c(i,j) = h_j - h_i$,其中 $h_i$ 表示第 $i$ 个导弹的高度。 最终的答案即为 $f(n)$,表示在第 $n$ 个导弹高度处放置拦截器的最小代价。 代码实现: 下面是拦截导弹问题的代码实现,时间复杂度为 $O(n^2)$: ```python def missile_defense_system(heights): n = len(heights) f = [float('inf')] * (n + 1) f[0] = 0 for i in range(1, n + 1): for j in range(i): cost = heights[j] - heights[i - 1] if cost < 0: continue if f[j] + cost < f[i]: f[i] = f[j] + cost return f[n] ``` 其中,`heights` 表示导弹的高度列表。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值