일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 플로이드와샬
- 에라토스테네스의 체
- BFS
- 이진탐색
- lca
- 삼분탐색
- 구현
- 그리디
- 백준
- 세그먼트트리
- 크루스칼
- 이분매칭
- 수학
- 다익스트라
- 정렬
- dfs
- 브루트포스
- 펜윅트리
- 좌표압축
- 비트마스크
- 누적합
- 위상정렬
- lis
- 투포인터
- 이분탐색
- DP
- MST
- DisjointSet
- LazyPropagation
- boj
Archives
- Today
- Total
lastknight00
[백준] 전깃줄-2(2568) 본문
문제 링크 : [백준] 전깃줄-2(2568)
문제 설명
두 전봇대 사이에 전깃줄이 연결되어있습니다.
한 전봇대에서 다른 전봇대로 연결된 전깃줄 중 교차되지 않도록 전깃줄을 제거해야합니다.
주어진 전깃줄 연결 중 서로 교차하지 않게 하면서 가장 작은수로 전깃줄을 제거하려면 어떤 전깃줄을 제거해야 하는지 출력하세요.
입력
N(전깃줄 갯수, 1 <= N <= 100,000)
Ai(왼쪽 전봇대의 위치, 1<= Ai <=500,000)
Bi(Ai와 연결되는 오른쪽 전봇대의 위치, 1<=Bi <=500,000)
8
1 8
3 9
2 2
4 1
6 4
10 10
9 7
7 6
출력
자르는 전깃줄 수와 자르는 전깃줄 위치(오름차순)
3
1
3
4
카테고리
#LIS #DP
시간 복잡도 상한
O(NlogN)
해결 방법
- 제거를 하는 방법은 너무 많습니다.
- 반대로 생각해보면, 최소로 제거를 한다는 것은, 최대로 연결된 전깃줄을 확보하는 것과 같습니다.
2-1. 최대로 연결된 전깃줄을 안다면, 그것에 포함되지 않는 것이 잘린 전깃줄입니다. - 전깃줄이 교차하지 않는다는 것은 왼쪽에서의 위치와 오른쪽에서의 위치가 서로 교차되지 않는다는 것입니다.
- 즉, 왼쪽 전봇대의 위치를 인덱스로 하고 오른쪽 위치를 값으로 하는 배열을 만들어 증가하는 최장 부분수열 LIS를 구하면 되는 문제입니다.
- 코드를 다시보니 굳이 저렇게 안하고 1차원 배열로 구현을 해도 될 것 같습니다.
- 단 NlogN LIS를 구할 경우, LIS를 구성하는 원소를 알 수 없어서 다른 장치가 필요합니다.
- LIS의 동작 원리를 생각해보면, lower_bound를 이용하여 위치를 찾아갈 때, 자신의 앞 위치는 항상 정확하게 찾을 수 있음을 알 수 있습니다.
- 따라서 lower_bound로 위치를 찾아가면서 앞 요소의 링크들을 저장하는 배열을 만듭니다.
- LIS 마지막 원소는 항상 가장 긴 원소의 마지막 요소이므로, 역추적하여 LIS 연결 요소들을 찾습니다.
- LIS 요소에 포함되지 않는 요소들을 출력하여 줍니다.
시간복잡도
O(NlogN)
코드
#include<cstdio>
#include<vector>
#include<algorithm>
#define pi pair<int,int>
#define mp make_pair
using namespace std;
int n,i,j,m;
pi p[100000];
int q[100000];
vector<pi> v;
bool comp(const pi &a,int b){
return a.first<b;
}
int main(){
scanf("%d",&n);
for(i=0;i<n;i++)scanf("%d %d",&p[i].first,&p[i].second);
sort(p,p+n);
for(i=0;i<n;i++){
if(v.empty()||v.back().first<p[i].second){
q[i]=v.size()?v[v.size()-1].second:-1;
v.push_back(mp(p[i].second,i));
m=i;
}else{
j=lower_bound(v.begin(),v.end(),p[i].second,comp)-v.begin();
q[i]=j?v[j-1].second:-1;
v[j]=mp(p[i].second,i);
}
}
printf("%d\n",n-v.size());
while(m>-1){
p[m].first=-1;
m=q[m];
}
for(i=0;i<n;i++)if(p[i].first>-1)printf("%d\n",p[i].first);
}
'PS' 카테고리의 다른 글
[백준] 가장 긴 바이토닉 부분 수열(11054) (0) | 2020.06.07 |
---|---|
[백준] 가장 긴 증가하는 부분 수열 5(14003) (0) | 2020.06.07 |
[백준] 소수상근수(9421) (0) | 2020.06.04 |
[백준] 피자 굽기(1756) (0) | 2020.06.04 |
[백준] 소수 사이 수열(3896) (0) | 2020.06.03 |
Comments