方法一:贪心算法
导弹的高度来决定拦截系统的高度,
每次更新已存在的拦截系统的高度,
如果没有大于等于导弹高度的拦截系统,
就再添加一个新的拦截系统。
代码实现:
#include<iostream>
#include<cstring>
using namespace std;
int a;
int b[100010];
int main()
{
int n,m;
while(scanf("%d",&n)!=EOF)
{
memset(b,0,sizeof(b));//初始化数组
m=0;//拦截系统的个数
for(int i=0;i<n;i++)
{
cin>>a;
int j;
for(j=0;j<=m;j++)//每次用较小的拦截系统来替换b中的数
{
if(b[j]>=a)
{
b[j]=a;
break;
}
}
if(j>m)//如果所有的拦截系统都不能拦截
{
b[++m]=a;//因为每次都是先遍历,再往后追加所以b数组中的数是从小到大排列的
}
}
cout<<m<<endl;
}
return 0;
}
附加:贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。
方法二:DP算法
这个题实际上就是求原序列的LIS(最长递增子序列),根据题意,我们可以先自己模拟一下拦截导弹的过程,然后定义状态dp[i](代表以第i个数为结尾的最长递增子序列的长度,也表示有多少个递减子序列)及dp[i]=max{0,dp[j]+1},0<j<i。答案为max{dp[i]}.
代码实现:
# include<stdio.h>
# include<algorithm>
# include<iostream>
# include<cstring>
using namespace std;
int dp[10050],h[10050];
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(dp,0,sizeof dp);
for(int i=1;i<=n;i++)
cin>>h[i];
int sum=0,max;
dp[1]=1;
for(int i=1;i<=n;i++)
{
max=0;
for(int j=1;j<=i;j++)
{
if(h[j]<h[i]&&max<dp[j])
{
max=dp[j];
}
dp[i]=max+1;
}
}
for(int i=1;i<=n;i++)
{
if(dp[i]>sum)
sum=dp[i];
}
cout<<sum<<endl;
}
return 0;
}
方法三:利用序列本身的性质通过一个辅助数组统计最长递增子序列的长度
这题可以单纯的看成dp求最长的递增序列长度(POJ 2533)的计算,大概就是先用数组定义所有的数字本来是自己包含的最长有序子列长度为1,然后用for循环来判断某个数字和它前面的数字的大小情况。如果是小于这个数的话,记录++;然后再先一个循环求出最长的那个序列
代码实现:
# include<stdio.h>
# include<iostream>
# include<algorithm>
# include<cstring>
using namespace std;
int main()
{
int n,f[1050],dp[1050];
while(~scanf("%d",&n))
{
memset(dp,0,sizeof dp);
for(int i=1;i<=n;i++)
cin>>f[i];
for(int i=1;i<=n;i++)
{
dp[i]=1;
for(int j=1;j<=i;j++)
{
if(f[j]<f[i])
dp[i]=max(dp[i],dp[j]+1);
}
}
int ans=-1;
for(int i=1;i<=n;i++)
{
if(ans<dp[i])
ans=dp[i];
}
cout<<ans<<endl;
}
return 0;
}