开始是单纯的用金典动归算法,果不其然超时了,然后没思路了!
错误代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string>
#include<string.h>
#include<cmath>
using namespace std;
#define max(a,b) a>b?a:b
int main()
{
int n,dp[100005],m[100005],i,j;
while(scanf("%d",&n)!=EOF)
{
for( i=0;i<n;i++)
{
scanf("%d",&m[i]);
dp[i]=1;
}
for( i=1;i<n;i++)
for( j=0;j<i;j++)
{
if(m[j]<=m[i])
dp[i]=max(dp[j]+1,dp[i]);
}
int ans=*max_element(dp,dp+n);
printf("%d\n",ans);
}
return 0;
}
然后看大神们的代码,表示看他们的代码和说明看不懂,然后我先粘贴过来自己调试运行一遍才知道他们说的到底是怎么回事,首先需要将数组最小的递增序(不懂没关系,下面我用数据说明)然后需要用二分查找,这儿是减小时间的重要步骤,大概就是这两个步骤;
先给出代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string>
#include<string.h>
#include<cmath>
using namespace std;
int dp[100005],a[100005];
int _find(int x,int len)
{
int left=0, right=len,middle;
while(left<=right)
{
middle=(left+right)/2;
if(dp[middle]==x)
return middle;
if(dp[middle]>x)
right=middle-1;
else
left=middle+1;
}
return left;
}
int main()
{
int n;
while(cin>>n)
{
for(int i=0;i<n;i++)
cin>>a[i];
int len=1;
dp[0]=a[0];
for(int i=1;i<n;i++)
{
if(a[i]>dp[len-1])
dp[len++]=a[i];
else
{
int t=_find(a[i],len);
dp[t]=a[i];
}
}
cout<<len<<endl;
}
return 0;
}
就拿第一组数据来说下:
输入时a(1 9 10 5 11 2 13 ),dp[0]=a[0],所以dp(1)
运行第一遍:因为a[1]=9>dp[0]=1 所以len=2,这时dp=(1,9);
运行第二遍:同上len=3,dp=(1 9 10);
运行第三遍:a[3]=5<dp[2]=10,不符合所以进入_find()函数(二分查找函数)返回值为1,具体情况模拟运行下就知道了,然后这时候dp=(1 5 10)
看到这里就看出来了于第二遍运行的结果是取最小的值既上面说的最小递增序列;
...........
最后的dp数列=(1 2 10 11 13)len=5;
大概就是这样,我很水,只能表达成这样了,见谅!