原题:
http://172.16.0.132/senior/#contest/show/1916/2
题目描述:
在很久以前,A国发明一套导弹拦截系统来防御敌国发射的导弹。这套系统能通过发射一枚导弹来拦截敌人的多枚导弹,但该导弹每次只能按距离由近到远拦截比它当前高度低(或等于当前高度)的导弹。
最近,有学者发现这套系统并不够强大,所以他们发明了另一套导弹拦截系统。同样的该系统也是发射一枚导弹拦截敌人的多枚导弹,并且也是由距离近的导弹向距离远的导弹进行拦截。当拦截导弹发射后,第一次它可选择任一枚导弹进行拦截,然后它可拦截比当前导弹距离远、高度低的导弹,接着它可拦截比当前导弹距离远、高度高的导弹……就是说,该拦截导弹在奇数次将拦截比前一枚导弹距离远、高度高的导弹,在偶数次将拦截比前一枚导弹距离远、高度低的导弹。
现在,有近到远给出了敌国发射过来的导弹的高度,请你计算出一枚该拦截导弹最多能拦截到多少枚导弹。
输入:
输入包含多组数据。对于每组数据,第一行是一个整数N,(1<=N<=1000),表示敌国发射的导弹数。接下来一行由近及远的给出N个整数h(0<=h<=10^9),表示导弹的高度。输入数据以N=0结束。
输出:
对于每组数据,输出一个整数,为一枚拦截导弹最多能拦截的导弹数量。
样例输入:
4
5 3 2 4
3
1 1 1
0
样例输出:
3
1
分析:
由题目给出:该拦截导弹在奇数次将拦截比前一枚导弹距离远、高度高的导弹,在偶数次将拦截比前一枚导弹距离远、高度低的导弹。
本题很易想到搜索,但题目给出敌国的导弹数可能是N<=1000的。
于是考虑使用动态规划:
这个题目从选择一个目标出发,然后有不同的拦截方法,由此我们可以把问题分解为:发射一枚导弹可以栏到那颗敌弹止,能栏到多少敌弹的子问题,由近到远进行求解这些子问题,找到一个最大值。
这个思路满足动态规划的解题条件:状态必须满足最优化原理和无后效性两个条件。
设:
max[i][1]表示当拦到第i枚敌弹时是第奇数次拦截,这时最多能拦到多少敌弹;
max[i][2]表示当拦到第i枚敌弹时是第偶数次拦截,这时最多能拦到多少敌弹;
Ans为最多拦截数量,num为输入的敌方导弹高度;
状态转移方程:
Max[i,2]:=max[j,1]+1;
当:num[j]>num[i],且有max[j,1]>max[i,2],j
实现:
#include<cstdio>
#include<iostream>
using std::max;
int n,i,j,a[1001],f[1001];
int main()
{
while(true)
{
scanf("%d",&n);
if(n==0) break;
for(i=1;i<=n;i++) scanf("%d",&a[i]);
for(i=1;i<=n;i++)
{
f[i]=1;
for(j=1;j<i;j++)
if(f[j]%2==1&&a[j]>a[i]||f[j]%2==0&&a[j]<a[i]) f[i]=max(f[i],f[j]+1);
}
printf("%d\n",f[n]);
}
}