N개의 구간이 입력으로 들어올 때, 아래 조건을 만족하는 가장 긴 서로 다른 구간의 수열을 찾으려 한다.
예를 들면 [1,10], [1,8], [2,7], [4,5] 는 위의 조건을 만족하는 수열이다.
구간의 끝 숫자에 대해 내림차순, 끝 숫자가 같다면 시작 숫자에 대해 오름차순으로 우선 정렬한다.
이렇게 정렬하고 나면 구간을 차례대로 살펴볼 때, 뒤에 나오는 구간(A)의 시작 시간이 앞에 있는 구간(B)보다 크거나 같다면 A는 B에 반드시 포함되게 된다.
예를 들어 아래와 같은 구간이 입력으로 주어졌다 하자.

이 구간들을 앞서 말한 조건대로 정렬시키면 아래와 같이 된다.

이때 보라색은 노란색과 시작 지점이 같으므로 노란색 구간에 포함되고, 마찬가지로 파란색은 보라색보다 시작 지점이 뒤에 있으므로 보라색 구간에 포함된다.
따라서 조건을 만족하는 가장 긴 구간의 수열을 구하려면
즉, lis와 유사한 문제인데 단지 차이는 같은 숫자도 수열에 포함될 수 있다는 것이다.
bool comp(const Interval a, const Interval b){
if(a.end == b.end) return a.start < b.start;
return b.end < a.end;
}
vector<int> minLast(N+2, INF);
int len = 0;
for(int i = 1; i <= N; i++){
int index = upper_bound(minLast.begin()+1, minLast.end(), intervals[i].start) - minLast.begin();
location[i] = index;
minLast[index] = intervals[i].start;
len = max(len, index);
}
[input]
7
1 7
2 7
3 7
3 7
5 7
3 6
4 6
[answer]
6
1 7
2 9
3 7
3 7
3 6
4 6
사실 이 글에서 말한 정렬 방법 말고, 시작 숫자에 대해 내림차순 -> 끝 숫자에 대해 오름차순 의 순서로 정렬 후, 구간들의 끝 숫자를 보며 lis(같은것 포함)를 구하는 방법도 가능하다.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define INF 987654321
struct Interval {
int start;
int end;
};
bool comp(const Interval a, const Interval b){
if(a.end == b.end) return a.start < b.start;
return b.end < a.end;
}
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
int N;
cin >> N;
vector<Interval> intervals(N+1);
for(int i = 1; i <= N; i++){
cin >> intervals[i].start >> intervals[i].end;
}
sort(intervals.begin()+1, intervals.end(), comp);
vector<int> minLast(N+2, INF);
vector<int> location(N+1);
int len = 0;
for(int i = 1; i <= N; i++){
int index = upper_bound(minLast.begin()+1, minLast.end(), intervals[i].start) - minLast.begin();
location[i] = index;
minLast[index] = intervals[i].start;
len = max(len, index);
}
cout << len << '\n';
vector<Interval> answer;
for(int i = intervals.size()-1; i >= 1; i--){
if(location[i] == len){
answer.push_back(intervals[i]);
len--;
}
}
for(auto iter = answer.rbegin(); iter != answer.rend(); iter++){
cout << iter->start << ' ' << iter->end << '\n';
}
return 0;
}
좋은 정보 얻어갑니다, 감사합니다.