https://programmers.co.kr/learn/courses/30/lessons/67260

 

코딩테스트 연습 - 동굴 탐험

9 [[0,1],[0,3],[0,7],[8,1],[3,6],[1,2],[4,7],[7,5]] [[8,5],[6,7],[4,1]] true 9 [[8,1],[0,1],[1,2],[0,7],[4,7],[0,3],[7,5],[3,6]] [[4,1],[5,2]] true 9 [[0,1],[0,3],[0,7],[8,1],[3,6],[1,2],[4,7],[7,5]] [[4,1],[8,7],[6,5]] false

programmers.co.kr

 

 

[난이도] level4
[유형] 그래프

[풀이]
우선 주어진 path로 인접 리스트를 만들었습니다. 풀이 중 필요없는 간선은 지워줄 것이기 때문에
vector가 아닌 set을 이용하였습니다.

order를 이용해 각 노드를 방문하려면 어떤 노드를 먼저 방문해야 하는지를 par 배열에 저장하였습니다.

풀이는 아래와 같습니다.

root부터 dfs를 돌리며 방문할 수 있는 노드 i를 방문하고 visit[i]=true 체크를 해줍니다.
방문할 수 없는 노드는 먼저 방문해야 하는 노드가 아직 방문하지 않은 상태로, visit[par[i]]==false인 상태입니다.
이 경우는 방문을 하지 않고 false를 return 해줍니다.

만약 모든 자식 노드들의 dfs 함수가 true를 return 했다면 모든 자식을 방문한 것이므로 현재 노드는 더이상 확인할 필요가 없습니다. 그러므로 인접 리스트로 사용되는 set에서 현재 노드와 부모 노드의 간선을 끊어줍니다.
위 제거 과정을 해주지 않으면 반복되는 dfs에 의해 시간 초과가 발생합니다.

이렇게 한 시행을 완료하였으면 새롭게 visit된 노드의 개수를 total에 더해줍니다.
만약 새롭게 visit된 노드가 있다면 이 노드가 visit되지 않아 이전 시행에서 방문하지 못했던 노드들도 이제 방문이 가능해진 것이기 때문에 다시 root부터 dfs를 돌리며 같은 시행을 반복합니다.

만약 visit된 노드 개수가 0이라면 더 이상 방문이 불가능하여 모든 노드를 방문할 수 없는 상태이므로 최종답으로 false를 return 합니다.

모든 노드를 방문해서 total==n 이 된다면 최종답으로 true를 return 해주면 됩니다.

#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <set>
using namespace std;
bool visit[200001];
set<int> adj[200001];
int par[200001],cnt,total;
bool sol(int prv, int n){
    if(par[n]!=-1 && !visit[par[n]]) return 0;
    if(!visit[n]) cnt++;
    visit[n]=1;
    bool ret=1;
    for(int nxt : adj[n]){
        if(nxt!=prv && !sol(n,nxt)) ret=0;
    }
    if(ret && n!=0) {
        adj[prv].erase(n);
        adj[n].erase(prv);
    }
    return ret;
}
bool solution(int n, vector<vector<int>> path, vector<vector<int>> order) {
    memset(par,-1,sizeof(par));
    for(auto& p : path) adj[p[0]].insert(p[1]), adj[p[1]].insert(p[0]);
    for(auto& o : order) par[o[1]]=o[0];
    while(1){
        cnt=0;
        sol(-1,0);
        if(cnt==0) return 0;
        total+=cnt;
        if(total==n) return 1;
    }
}

 

https://github.com/has2/Problem-Solving/blob/master/programmers/level4/[카카오_인턴]_동굴_탐험.cpp

 

 

 

※ 아래 링크의 카카오에서 제공하는 공식 풀이는 방향 그래프의 cycle 판별을 이용한 풀이입니다.
https://tech.kakao.com/2020/07/01/2020-internship-test/

cycle을 활용한 풀이 코드는 아래와 같습니다.

#include <vector>
using namespace std;
bool visit[200001],finished[200001];
vector<int> tadj[200001],adj[200001];
void dfs(int prv,int n){
    for(auto nxt : tadj[n]){
        if(prv!=nxt) {
            adj[nxt].push_back(n);
            dfs(n,nxt);
        }
    }
}
bool dfs2(int n){
    visit[n]=1;
    for(auto nxt : adj[n]){
        if(!visit[nxt]){
            if(!dfs2(nxt)) return 0;
        }else if(!finished[nxt]) return 0;
    }
    finished[n]=1;
    return 1;
}
bool solution(int n, vector<vector<int>> path, vector<vector<int>> order) {
    for(auto& p : path) tadj[p[0]].push_back(p[1]), tadj[p[1]].push_back(p[0]);
    dfs(-1,0);
    for(auto& o : order) adj[o[1]].push_back(o[0]);
    for(int i=0;i<n;i++) if(!visit[i] && !dfs2(i)) return 0;
    return 1;
}

 

 

 

https://www.acmicpc.net/problem/1068

 

1068번: 트리

첫째 줄에 트리의 노드의 개수 N이 주어진다. N은 50보다 작거나 같은 자연수이다. 둘째 줄에는 0번 노드부터 N-1번 노드까지, 각 노드의 부모가 주어진다. 만약 부모가 없다면 (루트) -1이 주어진다

www.acmicpc.net

[난이도] Gold5
[유형] 그래프

[풀이]
vector를 이용해 인접리스트를 만든 후 root에서부터 dfs로 순회를 해준다.
현재 노드가 삭제된 노드이면 0을 return하고, child가 empty이면 1을 return해준다.
예외처리 해주어야할 부분은 어떤 노드 n의 자식이 1개인데 이 노드가 삭제된 노드인 경우 n도 leaf 노드로 바꿔주어야 한다.

 

#include <cstdio>
#include <vector>
using namespace std;
int N,root,del;
vector<int> child[50];
int trvs(int n){
    if(n==del) return 0;
    if(child[n].empty()) return 1;
    int ret=0;
    bool f = 0;
    for(auto c : child[n]) {
        if(c==del) f=1;
        else ret+=trvs(c);
    }
    if(f && ret==0) return 1;
    return ret;
}
int main(){
    scanf("%d",&N);
    for(int i=0;i<N;i++){
        int par;
        scanf("%d",&par);
        if(par!=-1) child[par].push_back(i);
        else root=i;
    }
    scanf("%d",&del);   
    printf("%d",trvs(root));
} 

https://github.com/has2/Problem-Solving/blob/master/boj-solved.ac/Gold5/1068.cpp


https://www.acmicpc.net/problem/3584

 

3584번: 가장 가까운 공통 조상

루트가 있는 트리(rooted tree)가 주어지고, 그 트리 상의 두 정점이 주어질 때 그들의 가장 가까운 공통 조상(Nearest Common Anscestor)은 다음과 같이 정의됩니다. 두 노드의 가장 가까운 공통 조상은, 두

www.acmicpc.net

 

[난이도] Gold4
[유형] LCA

[풀이]
1. 공통 조상을 찾아야 하는 두 노드의 깊이를 구한다.
2. 깊이가 더 깊은 노드를 깊이 차이만큼 부모로 보내 깊이를 맞춰준다.
3. 깊이가 같아진 두 노드를 부모로 보내는 것을 반복하면서 두 노드가 같아지면
그 노드가 공통 조상이다.

 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int tc,N,par[10001],rt,p1,p2;
int getH(int n){
    int ret=0,cur=n;
    while(cur!=rt){
        cur=par[cur];
        ret++;
    }
    return ret;
}
int main(){
    scanf("%d",&tc);
    while(tc--){
        scanf("%d",&N);
        memset(par,0,sizeof(par));
        for(int i=1;i<N;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            par[b]=a;
        }
        scanf("%d%d",&p1,&p2);
        for(int i=1;i<=N;i++){
            if(par[i]==0) {
                rt=i;
                break;
            }
        }
        int p1h=getH(p1),p2h=getH(p2);
        if(p1h<p2h) {
            swap(p1,p2);
            swap(p1h,p2h);
        }
        for(int i=0;i<p1h-p2h;i++) p1=par[p1];
        while(p1!=p2){
            p1=par[p1];
            p2=par[p2];
        }
        printf("%d\n",p1);
    }
}



https://github.com/has2/Problem-Solving/blob/master/boj-solved.ac/Gold4/3584.cpp

+ Recent posts