P1020 [NOIP1999 普及组] 导弹拦截
题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入格式
1行,若干个整数
输出格式
2行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
分析:第一问为求最长不上升子序列,用dp实现
第二问贪心 ,用结构体维护每组导弹所能拦截的最小值,因为每次都要求出所有导弹系统能拦截的最小值中的最小值来进行判断能否用现有的系统兼容(最优地)
阴间代码:
#include<bits/stdc++.h>
const int maxn=505;
using namespace std;
int n,a[maxn],f[maxn];
int ans=-maxn;
int len=1,flag;
struct node
{
int d[105],top,lenz=0;
}e[105];
bool cmp(node xxx,node yyy)
{
return xxx.top<=yyy.top;
}
int main()
{
while(~scanf("%d",&a[++n])){}
for(int i=1;i<=n;++i)f[i]=1;
n--;
for(int i=2;i<=n;++i)
{
for(int j=1;j<i;++j)
{
if(a[i]<=a[j])
{
f[i]=max(f[i],f[j]+1);
}
}
}
for(int i=1;i<=n;++i)ans=max(ans,f[i]);
printf("%d\n",ans);
//d[len]=a[1];
e[len].top=a[1];
e[len].d[++e[len].lenz]=a[1];
for(int i=2;i<=n;++i)
{
flag=0;
sort(e+1,e+1+len,cmp);
for(int j=1;j<=len;++j)
{
if(e[j].top>=a[i])
{
e[j].top=a[i];
e[j].d[++e[j].lenz]=a[i];
flag=1;
break;
}
}
if(flag==0)
{
e[++len].top=a[i];
e[len].d[++e[len].lenz]=a[i];
}
}
printf("%d",len);
return 0;
}
另:(模版)最长不下降子序列
1.dp
#include<bits/stdc++.h>
using namespace std;
int a[10100],f[10100],n,maxn,ans[10100],num;
void print(int x)
{
if(!x) return;
print(ans[x]);
printf("%d ",a[x]);
}
int main()
{
while(scanf("%d",&a[++n])!=EOF)
{
}
for(int i=1;i<=n;i++)
{
f[i]=1;
}
{
n--;
for(int i=2;i<=n;i++)
for(int j=1;j<=i-1;j++)
{
if(a[i]>a[j])
{
if(f[i]<f[j]+1)
{
f[i]=f[j]+1;
ans[i]=j;//类似于图论的写法,存当前的上一位(链)
}
if(f[i]>maxn)
{
num=i;
maxn=f[i];
}
}
}
}
printf("max=%d\n",maxn);
print(num);
return 0;
}
注意:
有两个转移方程:
f[i]=max(f[i-1],f[j]+1) ------1
f[i]=max(f[i],f[j]+1) -------2
第一个方程f[i]求的是序列前i个中最长的不下降子序列长度,所以最后输出结果直接输出f[n]
第二个方程f[i]求的是这个点(i)能形成的最长不下降子序列,最后要有循环判出 i=1~n;ans=max(ans,f[i]);
2.模拟+二分 O(nlogn)
#include<bits/stdc++.h>
const int maxn=1005;
using namespace std;
int d[maxn],a[maxn],len;
int n;
/*int find(int st,int ed,int v)
{
int ret=ed;
while(st<=ed)
{
int mid=(st+ed)/2;
if(d[mid]>=v)
{
ret=mid;
ed=mid-1;
}
else st=mid+1;
}
return ret;
}*/
int main()
{
scanf("%d",&n) ;
for(int i=1;i<=n;++i)scanf("%d",&a[i]);
d[1]=a[1];
len=1;
for(int i=2;i<=n;++i)
{
if(a[i]>=d[len])d[++len]=a[i];
else
{
int temp=upper_bound(d+1,d+len+1,a[i])-d;//最长不下降
//int temp=find(l,len,a[i])
d[temp]=a[i];
}
}
printf("%d",len);
return 0;
}