线性dp

你离开我真会死。 提交于 2020-02-02 23:29:54

拦截导弹(acwing.1010)

【题意】:某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,导弹数不超过1000),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

【分析】:第一个输出直接LIS就行,对于第二个问要考虑贪心思想,考虑一个拦截系统,起最后一个的高度肯定越大越有利于后面的元素增加进来,所需要的系统肯定就越少。所以用一个g数组来维护其最小元素的最大值,元素的个数就是最终所需的最少的拦截系统的个数。

#include <cstdio>
#include <algorithm>
#include <cstdlib>

using namespace std;
const int maxn=1e3+10;
int arr[maxn],t,dp[maxn];
int g[maxn];

int main()
{
    int tot=0;
    while (~scanf("%d",&t)){
        arr[++tot]=t;
    }
    int ans=0;
    for(int i=1;i<=tot;++i){
        dp[i]=1;
        for(int j=1;j<i;++j){
            if(arr[j]>=arr[i])   dp[i]=max(dp[i],dp[j]+1);
            ans=max(ans,dp[i]);
        }
    }
    printf("%d\n",ans);
    ans=0;
    //贪心,g数组维护最大的最短长度
    for(int i=1;i<=tot;++i){
        int k=1;
        while (k<=ans&&g[k]<arr[i])  k++;
        g[k]=arr[i];
        if(k>ans)   ans++;
    }   
    printf("%d\n",ans);
    system("pause");
}

导弹防御系统(acwing.187)

【题意】:为了对抗附近恶意国家的威胁,R国更新了他们的导弹防御系统。一套防御系统的导弹拦截高度要么一直上升要么一直下降。例如,一套系统先后拦截了高度为3和高度为4的两发导弹,那么接下来该系统就只能拦截高度大于4的导弹。给定即将袭来的一系列导弹的高度,请你求出至少需要多少套防御系统,就可以将它们全部击落。

样例输入(n<=50):

5
3 5 2 4 1
0 

样例输出:

2

【分析】:对于每一个元素,它只有两种状态:属于上升拦截系统或者属于下降拦截系统,所以用一个 dfs 既可以枚举所有状态;直接 dfs 其时间复杂度肯定超时(2^50),所以随便剪剪枝就好了。

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;
const int maxn=55;
int arr[maxn],n,up[maxn],down[maxn];
int ans;
void dfs(int u,int d,int num)   //u为上升系统的个数,d为下降系统的个数,num为数组中低级个数
{
    if(u+d>=ans)    return;
    if(num==n){
        ans=u+d;
        return;
    }
    int k=1;
    //属于上升子序列
    while (up[k]>=arr[num]&&k<=u) k++;
    int t=up[k];
    up[k]=arr[num];
    if(k>u)   dfs(u+1,d,num+1);
    else dfs(u,d,num+1);
    up[k]=t;
    k=1;
    //属于下降子序列
    while (down[k]<=arr[num]&&k<=d)   k++;
    t=down[k];
    down[k]=arr[num];
    if(k>d)   dfs(u,d+1,num+1);
    else dfs(u,d,num+1);
    down[k]=t;
    k=1;
}

int main()
{
    while(~scanf("%d",&n)&&n){
        for(int i=1;i<=n;++i)   scanf("%d",&arr[i]);
        memset(up,0,sizeof(up));
        memset(down,0,sizeof(down));
        ans=n;
        dfs(0,0,1);
        printf("%d\n",ans);
    }
    //system("pause");
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!