일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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
- dfs
- 비트마스크
- 펜윅트리
- 세그먼트트리
- 구현
- 정렬
- 수학
- 이분매칭
- 에라토스테네스의 체
- 투포인터
- 누적합
- DP
- lis
- 브루트포스
- DisjointSet
- boj
- lca
- 삼분탐색
- 위상정렬
- 이분탐색
- 좌표압축
- 플로이드와샬
- 다익스트라
- MST
- 백준
- 그리디
- 크루스칼
- BFS
- 이진탐색
- LazyPropagation
Archives
- Today
- Total
lastknight00
[백준]사회망 서비스(SNS)(2533) 본문
문제 링크 : [백준]사회망 서비스(SNS)(2533)
문제 설명
N개의 노드로 이루어진 트리가 주어지고, 각 노드는 얼리어답터이거나 자신과 인접한 모든 노드들이 얼리어답터이어야 합니다.
적당히 얼리어답터를 선정했을 때 위 조건을 만족하도록 만들어야 하는데, 그때 최소로 얼리어답터를 지정할 수 있는 수가 몇명인지 구하세요.
입력
N(노드의 수, 2 <= N <= 1,000,000)
Ui Vi(간선 정보)
8
1 2
1 3
1 4
2 5
2 6
4 7
4 8
출력
3
카테고리
#DP #트리
시간 복잡도 상한
O(NlogN)
해결 방법
- 모든 사람들에 대하여 얼리어답터인 경우와 얼리어답터가 아닌 경우를 대입하보면 구할 수 있습니다.
- 부모 노드의 얼리어답터 여부에 따라서 두가지 경우로 나누어집니다.
- 부모 노드가 얼리어답터인 경우, 자식 노드들은 얼리어답터가 되어도 되고, 얼리어답터가 아니어도 됩니다.
- 부모 노드가 얼리어답터가 아닌 경우, 자식 노드는 반드시 얼리어답터가 되어야합니다.(인접한 노드 중 적어도 하나가 얼리어답터가 아니기 때문(부모))
- 루트를 시작으로, 각 자식 노드들을 루트로 하는 서브트리로 만들어서, 위 두가지 경우에 대하여 최소가 되는 서브트리들의 값들을 취합합니다.다음과 같은 재귀 함수가 정의 될 수 있습니다.
int r(int p,int s){ int value=0; w[p]=1; for(int i=0;i<v[p].size();i++){ if(w[v[p][i]])continue;//이미 방문한 노드(부모)라면 무시함 int temp=r(v[p][i],1);//자식 노드를 루트로 하는 서브트리에 대하여, 자식이 얼리어답터인 경우의 최소 얼리어답터 수를 구함 if(s==1)temp=min(r(v[p][i],0),temp);//자신이 얼리어답터인 경우에 한하여, 자식 노드를 루트로 하는 서브트리에 대하여, 자식이 얼리어답터가 아닌 경우의 최소 얼리어답터 수를 구함 value+=temp; } w[p]=0; return value; }
-
하지만 시간복잡도가 O(2N)이기 때문에 타임아웃이 납니다.
- 그러나 호출 관계를 따지다 보면 중복된 경우에 대한 호출이 빈번함을 알 수 있습니다.
- 또한 K번 노드가 얼리어답터 이거나 얼리어답터가 아닌 경우에 대하여 자신을 포함한 하위 노드들에 대한 최소 얼리어답터 수는 고정이 되어 있습니다.
- 따라서 함수 호출에 대하여 매번 계산 할 것이 아니라, 메모이제이션을 이용하여 함수 호출 횟수를 줄일 수 있습니다.
시간복잡도
O(N)
코드
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
int n,x,y,i,d[2][1000001],w[1000001];
vector<int> v[1000001];
int r(int p,int s){
if(d[s][p])return d[s][p];
w[p]=1;
for(int i=0;i<v[p].size();i++){
if(w[v[p][i]])continue;
d[s][p]+=min(r(v[p][i],1),s?r(v[p][i],0):1000002);
}
d[s][p]+=s;
w[p]=0;
return d[s][p];
}
int main(){
scanf("%d",&n);
for(;i<n-1;i++){
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
printf("%d",min(r(1,0),r(1,1)));
}
'PS' 카테고리의 다른 글
[백준]화려한 마을(12895) (0) | 2020.08.30 |
---|---|
[백준]직각다각형(17611) (0) | 2020.08.26 |
[백준]K번째 최단경로 찾기(1854) (0) | 2020.08.16 |
[백준]거의 최단 경로(5719) (0) | 2020.08.16 |
[백준]할로윈 묘지(3860) (0) | 2020.08.16 |
Comments