题目:http://poj.org/problem?id=2533
求最长上升子序列。
N^2 dp:
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int a[1005],dp[1005];
int main() {
int n,ans;
while(scanf("%d",&n)!=EOF){
ans=1;
for(int i=0;i<n;i++){
cin>>a[i];
dp[i]=1;
}
for(int i=1;i<n;i++){
for(int j=0;j<i;j++)
if(a[i]>a[j])
dp[i]=max(dp[j]+1,dp[i]); //用dp[j]+1得到一个新的最大长度,看看谁是最大的。
ans=max(dp[i],ans);
}
cout<<ans<<endl;
}
return 0;
}
nlogn:想个办法把第二重循环做成二分即可,加个有序的long数组
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int Max,n,a[1005],Long[1005]; //以序列号为下标,存放a[]下标,显然单调递增,为了可以二分
int Link[1005]; //链接最长序列,储存相连接的下标
int Find(int x){ //找最后一个比x小的
int l=1,r=Max; //long最短长度是1,下标从1开始,wa了好久
while(l<r){
int mid=(l+r)/2;
if(a[Long[mid]]<x)
l=mid+1;
else
r=mid;
}
return l-1;
}
int main() {
while(scanf("%d",&n)!=EOF){
memset(Long,0,sizeof(Long));
memset(Link,0,sizeof(Link));
for(int i=0;i<n;i++)
cin>>a[i];
Max=1; Long[1]=0; Link[0]=0;
for(int i=1;i<n;i++){
if(a[i]>a[Long[Max]]){
Max++;
Long[Max]=i;
Link[i]=Long[Max-1];
}
else{
int l=Find(a[i]);
Long[l+1]=i; //这里长度要是和Max一样,就自动替换了
Link[i]=Long[l];
}
}
cout<<Max<<endl;
//输出序列
/*cout<<a[Long[Max]]<<" ";
for(int i=Link[Long[Max]];Max>1;i=Link[Long[--Max]])
cout<<a[i]<<" ";*/
}
return 0;
}
还有一种和上法差不多,用堆栈边++top堆边换,换的时候可以用二分。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int Stack[1005];
//堆栈,还是往里塞,大于top入栈,否则找到比他大的第一个数替换
int main() {
int n;
while(scanf("%d",&n)!=EOF){
int top=0,temp,l,r;
Stack[0]=-1; //栈顶第一个元素可能为0
for(int i=0;i<n;i++){
cin>>temp;
if(temp>Stack[top])
Stack[++top]=temp; //从1开始
else{
l=1,r=top;
while(l<r){
int mid=(l+r)/2;
if(temp>Stack[mid])
l=mid+1;
else
r=mid;
}
Stack[l]=temp;
}
}
cout<<top<<endl;
}
return 0;
}