题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1257
题目大意:为了预防敌国导弹的袭击,某国开发了一个拦截系统,这种系统有这些特点,首先第一次可以发射任意高度的导弹去拦截,但是随后的导弹高度不能超过前一个,现在给出一些敌国的导弹高度,求出需要最少的拦截系统数目;
首先这道题我们需要去理解题意,文字好像不太好解释,所以我们直接拿数据说明;
8 300 207 180 299 299 170 171 60
8代表有8个导弹这个我们先不看,后面8个值就是的导弹的高度,300 207 180肯定需要一个拦截系统然后的话299 299 170 也需要一个拦截系统,那么最后的171 60是不是也需要呢?如果理解了题目的话这个其实是不需要的,因为可以放在第一个拦截系统里,即300 207 180 171 60所以说答案就是2个拦截系统;
在这里给出dp,贪心,LIS等三种方法;
DP:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int Max = 0x3f3f3f3f;
const int Min = 0xc0c0c0c0;
const int maxn = 123456;
#define mst(a) memset(a,0,sizeof(a))
#define w(i) while(i--)
#define forij(i,j,k,step) for(int i=k;i<j;i+=step)
int t,n,m;
int a[maxn];
int dp[maxn];//存放需要的系统数
int main()
{
int n;
while(~scanf("%d",&n))
{
for(int i=0; i<n; i++)
{
scanf("%d",&a[i]);
dp[i]=1;//刚开始每一个导弹需要1个系统
}
for(int i=1; i<=n; i++)
{
for(int j=0; j<i; j++)//与前面每一个比较一次
{
if(a[j]<a[i])//需要多加1个系统
dp[i]=max(dp[i],dp[j]+1);//选出需要最少系统的最大值
}
}
sort(dp,dp+n);
cout<<dp[n-1]<<endl;
}
return 0;
}
贪心:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int Max = 0x3f3f3f3f;
const int Min = 0xc0c0c0c0;
const int maxn = 123456;
#define mst(a) memset(a,0,sizeof(a))
#define w(i) while(i--)
#define forij(i,j,k,step) for(int i=k;i<j;i+=step)
int t,n,m;
int dp[maxn];//存放需要的系统数
int main()
{
while(~scanf("%d",&n))
{
int x,sum=0;
dp[maxn]={0};
for(int i=0;i<n;i++)
{
cin>>x;int j;
for(j=1;j<=sum;j++)
{
if(x<=dp[j])
{
dp[j]=x;//更新该系统下一个能拦截的最大高度
break;
}
}
if(j>sum) //前面的系统不能拦截
{
dp[++sum]=x;//新加一个系统并且赋值下一次能拦截的高度
}
}
cout<<sum<<endl;
}
return 0;
}
LIS:
这里需要讲一个结论那就是我们所求的拦截系统的数目其实就是下降子序列的数目,然后下降子序列的数目又会等于最长上升子序列中所含元素的个数;、
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int Max = 0x3f3f3f3f;
const int Min = 0xc0c0c0c0;
const int maxn = 123456;
#define mst(a) memset(a,0,sizeof(a))
#define w(i) while(i--)
#define forij(i,j,k,step) for(int i=k;i<j;i+=step)
int t,n,m;
int dp[maxn];
int a[maxn];
int main()
{
while(scanf("%d",&n)&&n)
{
int ans=0;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
dp[1]=1;
for(int i=1;i<n;i++)
{
int m=0;
for(int j=0;j<i;j++)
{
if(dp[j]>m&&a[j]<a[i])
{
m=dp[j];
}
dp[i]=m+1;
}
if(dp[i]>ans)
{
ans=dp[i];
}
}
cout<<ans<<endl;
}
return 0;
}
最后在给个最简单的代码,这个代码思想和贪心没什么区别,只是实现的方式很奇妙;
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
const double eps = 1e-6;
const int Max = 0x3f3f3f3f;
const int Min = 0xc0c0c0c0;
const int maxn = 123456;
#define mst(a) memset(a,0,sizeof(a))
#define w(i) while(i--)
int t,n,m;
int a[maxn];
int dp[maxn];
int main()
{
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
{
cin>>a[i];
dp[i]=Max;
}
for(int i=0;i<n;i++)
{
*lower_bound(dp,dp+n,a[i])=a[i];
}
cout<<lower_bound(dp,dp+n,Max)-dp<<endl;
}
return 0;
}