주어진 수열에서 최장 등차수열을 찾는 문제이다. 최근에 푼 문제 중에서 제법 어려운 편인것 같다.
일단 d[i][j]를 수열에서 i번째수와 j번째수로 시작하는 등차수열의 최대 길이로 잡았다. 이 발상을 하는데 혼자 고민을 한시간 넘게했다.
그 후에 동적 계획법 함수 dp 안에서 first, second로 third를 찾는데 순차 탐색을 하니 전체 시간복잡도가 O(n^3)이 되어서 시간이 모자랐다. 시간 문제를 해결 하기위해 순차 탐색 대신에 이진탐색을 수행하였는데 여기서도 예외가 발생했다. 같은 수가 여러개 있는 상황을 고려하지 못했다. third가 될 수 있는 수가 여러개가 있다면 가장 왼쪽의 수를 선택해야한다. 이는 stl::low_bound 함수로 구현했다.
d[first][second] : first번째 수와 second번째수로 시작하는 등차 수열의 최대 길이.
d[first]second] = d[second][third] + 1 (third는 이진탐색으로 찾음)
시간 복잡도 : O(n^2 log n)
#include <iostream>
#include <vector>
#include <cstdio>
#include <algorithm>
#include <memory.h>
using namespace std;
int C,t;
vector<int> seq;
int d[2001][2001];
int dp(int first, int second)
{
int &ret = d[first][second];
if(ret != -1) return ret;
int idx = -1;
int third = 2*seq[second]-seq[first]
auto low = lower_bound(seq.begin()+second+1,seq.end(), third );
if(low != seq.end() && *low == third ) idx = low-seq.begin();
if(idx == -1) return ret = 2;
else return ret = 1+dp(second, idx);
}
int main()
{
scanf("%d",&C);
for(int i=0; i<C; i++)
{
scanf("%d",&t);
seq.push_back(t);
}
sort(seq.begin(),seq.end());
memset(d,-1,sizeof(d));
int ans = 1;
for(int i=0; i<C; i++)
{
for(int j=i+1; j<C; j++)
{
ans = max(ans,dp(i,j));
}
}
cout<<ans;
}
'알고리즘 > BOJ문제풀이' 카테고리의 다른 글
345번째 문제 - 3042번 트리플렛 (0) | 2017.01.18 |
---|---|
1520 내리막길 (0) | 2016.12.30 |
272번째 문제 - 2494 숫자 맞추기 (0) | 2016.12.22 |
227번째 문제 - 1967 트리의 지름 (0) | 2016.12.16 |
217번째 문제 - 2306 유전자 (0) | 2016.12.14 |