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