SDNU 1040.导弹拦截

2 篇文章 0 订阅

SDNU 1040.导弹拦截

Time Limit: 1000 MS Memory Limit: 32768 KB
Total Submission(s): 333 Accepted Submission(s): 82
Description
某国为了防御敌国的导弹袭击,研发出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试验阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

Input
输入数据只有一行,该行包含若干个数据,之间用半角逗号隔开,表示导弹依次飞来的高度(导弹最多有 20 枚,其高度为不大于 30000 的正整数)。

Output
输出数据只有一行,该行包含两个数据,之间用半角逗号隔开。第一个数据表示这套系统最多能拦截的导弹数;第二个数据表示若要拦截所有导弹至少要再添加多少套这样的系统。

Sample Input
389,207,155,300,299,170,158,65

Sample Output
6,1

Source
Unknown

这是一道非常典型的最长下降子序列题,前半部分非常简单,只要把输入的东西分别从到数组里就可以了,但是后半部分确实难道我了,一开始是想到用贪心的,但是写了半天写不出来(留下来不学无术的眼泪)。之后突发奇想,用vector存储所有导弹的高度,然后输出最长下降子序列,之后把这一串最长下降子序列里所有元素删掉,再重复以上操作直到被清空(直男做法)。
附上代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>

using namespace std;

int s[1001]= {0},dp[1001]= {1},lenn,js=0,pos[1001],m;
vector<int> cc;
char n[1000];

void LIS()
{
    dp[0]=cc[0];
    int len=0;
    pos[0]=len;
    for(int i=1; i<js; i++)
    {
        if(cc[i]<=dp[len])
        {
            dp[++len]=cc[i];
            pos[i]=len;
        }
        else
        {
            int j;
            for(j=0; j<=len; j++)
            {
                if(dp[j]<=cc[i])
                {
                    break;
                }
            }
            dp[j]=cc[i];
            pos[i]=j;
        }
    }
    int an[101],ann=0;
    for(int i=js-1; i>=0; i--)
    {
        if(len<0)
            break;
        if(pos[i]==len)
        {
            an[ann]=cc[i];
            ann++;
            len--;
        }
    }
    for(int i=0; i<ann; i++)
    {
        int temp=cc.size();
        for(int j=temp-1; j>=0; j--)
        {
            if(an[i]==cc[j])
            {
                //cout<<*(cc.begin()+j)<<' ';
                cc.erase(cc.begin()+j);
                js--;
                break;
            }
        }
    }
}

int main()
{
    gets(n);
    lenn=strlen(n);
    for(int i=0; i<lenn; i++)
    {
        if(n[i]<='9'&&n[i]>='0')
        {
            s[js]=s[js]*10+n[i]-48;
        }
        else if(n[i]==',')
            js++;
    }
    js++;
    for(int i=0; i<js; i++)
        cc.push_back(s[i]);
    dp[0]=cc[0];
    int len=0;
    pos[0]=len;
    for(int i=1; i<js; i++)
    {
        if(cc[i]<=dp[len])
        {
            dp[++len]=cc[i];
            pos[i]=len;
        }
        else
        {
            int j;
            for(j=0; j<=len; j++)
            {
                if(dp[j]<=cc[i])
                    break;
            }
            dp[j]=cc[i];
        }
    }
    cout<<len+1<<',';
    int sum=0;
    while(!cc.empty())
    {
        memset(dp,0,sizeof(dp));
        memset(pos,0,sizeof(pos));
        LIS();
        //cout<<cc.size()<<endl;
        sum++;
    }
    cout<<sum-1<<endl;
    return 0;
}

对于前半部分的代码应该是可以压缩到 LIS() 这个函数里面的,但是因为我这个思想比较奇怪,也没有去做优化。问了队里的大佬,终于用贪心写出来了(鬼贪心还写了这么久,听说还有dp的方法,以后再想吧!)

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

using namespace std;

int f[105],dp[105],last[105];
char n[105];
int main()
{
    int x,ans=0,js=1;
    gets(n);
    int lenn=strlen(n);
    for(int i=0; i<lenn; i++)
    {
        if(n[i]<='9'&&n[i]>='0')
        {
            f[js]=f[js]*10+n[i]-48;
        }
        else if(n[i]==',')
        {
            js++;
        }
    }
    f[0]=js;
    for (int i=0; i<=f[0]; i++)
        for (int j=0; j<i; j++)
            if (f[j]>=f[i])
                dp[i]=max(dp[i],dp[j]+1);
    for (int i=1; i<=f[0]; i++)
        dp[0]=max(dp[0],dp[i]);
    cout<<dp[0]+1)<<',';
    for (int i=1; i<=f[0]; i++)
    {
        bool flag=0;
        for (int j=1; j<=ans;j++)
            if (last[j]>=f[i])
            {
                last[j]=f[i];
                flag=1;
                break;
            }
        if (!flag)
        {
            ans++;
            last[ans]=f[i];
        }
    }
    cout<<ans-1<<endl;
    return 0;
}

这个思想就是一开始的时候只放一个系统,全部扫过一遍之后,如果某个导弹可以加入某个系统,就把它加进去,否则就多开一个新的系统。思想和一开始我想的差不多,但就是想不出来,看来还是要多多练习啊!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值