好像好几天没有写题解了,今天补一补
题目描述
题目:https://vjudge.net/problem/HDU-1257
中文题目,我就不多说了。
思路分析
这道题可以用贪心,也可以用dp。
贪心
可以这样想:有无数个防御系统,高度无限高,每次来一颗导弹,都去找高度比它高但又最接近的(>=中最小的)一个系统攻击,最后统计有多少个导弹系统不是无限高。
这里有个问题:怎么找到最接近的那个呢?首先,在这个思路里,每个系统需要记下的只是现在它能打到的最大高度,顺序并不重要,因此,我们可以每次都sort一次,然后用lower_bound,二分查找到要找的那个系统进行操作,这样就避免了找系统的时候的各种繁琐操作了。
完整代码(贪心)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=30005;
int main()
{
int n;
while(cin>>n)
{
vector<int> daodan;
daodan.clear();
daodan.push_back(30005);
int maxnum=30005;
for(int i=0;i<n;i++)
{
int t;
cin>>t;
if(maxnum>=t)
{
int i=lower_bound(daodan.begin(),daodan.end(),t)-daodan.begin();
daodan[i]=t;
}
else
{
daodan.push_back(t);
maxnum=t;
}
sort(daodan.begin(),daodan.end());
maxnum=daodan[daodan.size()-1];
}
cout<<daodan.size()<<endl;
}
return 0;
}
dp
这道题也可以是看作这样:找到最长的递减序列,删掉这里的元素,然后反复这个过程,计算一共进行了多少次,得到需要的系统数。
但是,这个算法需要很多删除的操作,耗时较大。
再进一步分析:其实,对于每一个序列,序列中递增序列的长度就是不下降序列数。为什么呢?拿样例来说:
8 389 207 155 300 299 170 158 65
找到的两个递减序列是:
389 207 155 158 65
300 299 170
那个,在第一个序列中总能找到一个数:它会小于第二个序列中的某个数。
因此,我们可以得到这个结论:一个数列的LIS的长度等于该数列非上升子序列数目。
因此,我们可以用lis算法来得到答案。
完整代码(dp)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100000;
int dp[maxn];
int heigh[maxn];
int n;
int make()
{
int ans=1;
dp[1]=1;
for(int i=2;i<=n;i++)
{
int Max=0;
for(int j=1;j<i;j++)
{
if(heigh[j]<heigh[i]&&dp[j]>Max)
{
Max=dp[j];
}
}
dp[i]=Max+1;
ans=max(dp[i],ans);
}
return ans;
}
int main()
{
while(cin>>n)
{
memset(dp,0,sizeof(dp));
memset(heigh,0,sizeof(heigh));
for(int i=1;i<=n;i++)
{
cin>>heigh[i];
}
cout<<make()<<endl;
}
return 0;
}