题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1257
这段时间在做专题训练,所以就刻意挑了挑动态规划做。
题目一看就知道是跟最长单调递减类似,简单的动态规划。
代码:
#include<stdio.h>//**dp[i]表示第i个导弹飞过来时需要的最少拦截装置.**//
int main()
{
int n,i,j,max,h[10001],dp[10001];
while(~scanf("%d",&n))
{
max=-1;
dp[0]=0;
for(i=1;i<=n;i++)
{
scanf("%d",&h[i]);//**飞来的高度**//
dp[i]=1;//**初始化拦截装置都为1**//
}
for(i=1;i<=n;i++)
{
for(j=i-1;j>=0;j--)
{
if(h[i]>h[j]&&dp[i]<dp[j]+1)//**如果在拦截中出现了非单调递减的**//
{
dp[i]=dp[j]+1;
}
}
}
for(i=1;i<=n;i++)
{
if(dp[i]>max)
{
max=dp[i];
}
}
printf("%d\n",max);
}
return 0;
}
还可以用贪心来做,其实方法还是类似的,找了段便于理解的解释就直接贴出来了。对于这个题目的测试例的解释:当8枚导弹依次飞来时,对于前三枚导弹(300,207,155),用第一套系统即可拦截,每一次更新记录,即:对第一枚导弹直接拦截,第二枚导弹来临时也用第一套系统拦截,记录改变成207,当用第一套系统拦截第三枚后记录修改为155,当第四枚导弹来时按照系统规定,第一套系统无法实现对第四枚导弹的拦截任务,因此,开第二套系统,为了使用最少系统,必须对以后的每一枚导弹贪心,即:拿这枚导弹和以前的导弹最小记录依次做比较,寻找一个和这枚导弹高度最接近的记录并用这枚导弹的高度替换原记录,最后记录数组中的个数就是最少需要的系统数。
其实在纸上写写就会发现以前导弹的最小记录按拦截记录来比较都是最小的。意思就是假如前面的拦截装置能够拦截就一定不需要判断后面的是否需要拦截,一定不需要拦截,依次类推(贪心);
代码:
#include<stdio.h>
int main()
{
int n,x,i,j,min,count,flag,a[10001];
while(~scanf("%d",&n))
{
count=0;
for(i=1;i<=n;i++)
{
flag=0;//***标记元素**//
scanf("%d",&x);
min=30005;
for(j=0;j<=count-1;j++)
{
if(a[j]>x&&min>a[j]-x)//**保证是和这个导弹最接近的**//
{
min=a[j]-x;
a[j]=x;
flag=1;
}
}
if(flag==0)
{
a[count]=x;
count++;
}
}
printf("%d\n",count);
}
return 0;
}
还有一题差不多的,直接求单调递减的最大个数。
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=79
直接上代码:
#include<stdio.h>
int main()
{
int s,n,i,j,max,h[101],dp[101];
scanf("%d",&s);
while(s--)
{
max=-1;
dp[0]=0;
scanf("%d",&n);
for(i=0;i<=n-1;i++)
{
scanf("%d",&h[i]);
dp[i]=1;
}
for(i=1;i<=n-1;i++)
{
for(j=i-1;j>=0;j--)
{
if(h[i]<h[j]&&dp[i]<dp[j]+1)
{
dp[i]=dp[j]+1;
}
}
}
for(i=0;i<=n-1;i++)
{
if(dp[i]>max)
{
max=dp[i];
}
}
printf("%d\n",max);
}
return 0;
}