http://poj.org/problem?id=2533
O(n*n) 算法的状态转移公式:dp[i] = max{dp[j] + 1}, j < i and a[j] < a[i]. 以i结尾的序列的LIS,等于a[0] - a[i - 1] 序列中的LIS 再加1(a[i])。
O(n*logn)算法:记录以a[i]结尾的,长度为j 的LIS,最小的末尾元素dp[j]。通过二分查找,在dp中找出刚好小于a[i]的元素dp[j]. 参见 http://www.felix021.com/blog/read.php?1587
//Accepted
#include <iostream>
using namespace std;
int a[1005];
int dp[1005];
int main()
{
int n;
cin >>n;
for(int i = 0; i < n; ++i) {
cin >>a[i];
dp[i] = 1;
}
int len = 1;
for(int i = 1; i < n; ++i) {
for(int j = 0;j < i; ++j) {
if(a[j] < a[i] && dp[i]< dp[j] + 1)
dp[i]= dp[j] + 1;
}
if(len < dp[i])
len = dp[i];
}
cout <<len;
return 0;
}
另附上Wrong answer的一段代码,以后code过程中要注意
int len = 1;
for(int i = 1; i < n; ++i) {
int max = 0;
for(int j = 0;j < i; ++j) {
if(a[j] < a[i] && max < dp[j] + 1)
max = dp[j] + 1;
}
dp[i] = max;
if(len < dp[i])
len = dp[i];
}
cout <<len;
在第一个for循环里面,定义了max用来记录dp[j] + 1, j <i 的最大值。题目中给出了序列可以通过,另测试几个也可以。
但是注意,加入根本不进入内层for循环,或者进去了if一直为假,导致dp[i] = 0; e.g. 6 4 5的结果为1,而不是2.
另附上一段O(n*logn)的代码,本来昨天一直Wrong answer,今天回来一次就A了。
for(int i = 1; i <= n; ++i) {
cin >>a[i];
dp[i] = 0;
}
int len = 1;
dp[1] = a[1];
for(int i = 2; i <= n; ++i) {
left = 1;
right = len;
while(left <= right) {
mid = (left + right) / 2;
if(dp[mid] < a[i])
left = mid + 1;
else
right = mid - 1;
}
dp[left] = a[i];
if(len < left)
len++;
}