백준 코딩

최소 스패팅 트리 와 다익스트라 정리

까르르꿍꿍 2023. 6. 29. 17:21

오랜만에 문제를 풀다가 헷갈리는 부분들이 있어서 정리를 해본다.. 

 

 

최소 스패팅 트리

  • 모든 노드에서 가중치 합이 가장 작은 트리를 만드는 것

크루스칼 vs 프림

크루스칼 알고리즘

  • 간선의 길이가 짧은 것 부터 시작해서 사이클이 생기지 않게 간선을 추가하는 방식

프림 알고리즘

  • 한 시작 노드를 정한 후에 노드에 연결된 간선 중 최소 값을 선택하여 확장해나가는 방식

 

크루스칼 알고리즘 구현 

// 유니온 파인트도 사이클 체크
int findparent(int x){
    if(x==findparent(parent[x])){
        return x;
    }else{
        return parent[x]=findparent(parent[x]);
    }
}
void uni(int x,int y){
    x=findparent(x);
    y=findparent(y);
    parent[y]=x;
}
void solution(){
    
    for(int i=1; i<=n; i++) parents[i] = i;
    sort(edges.begin(), edges.end(), cmp);
    
    for(int i=0; i<edges.size(); i++){
        int node1 = edges[i].second.first;
        int node2 = edges[i].second.second;
        int cost = edges[i].first;  
        
        if(get_parent(node1) != get_parent(node2)){. // 사이클이 안만들어지면 간선 추가
            union_parents(node1, node2);
            total -= cost;       //total은 총 가중치 합 
        }
    }
    
}

 

 

프림 알고리즘 구현(우선순위 큐)

void prim(int start){
    visited[start]=true;    //오름차순 우선순위 큐 사용
    priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> pq;
    for(int i=0;i<v[start].size();i++){
        int dis=v[start][i].first;
        int node=v[start][i].second;
        pq.push({dis,node});   //시작 노드에서 이어지는 간선들 큐에 삽입
    }
    while(!pq.empty()){
        int dis=pq.top().first;
        int node=pq.top().second;
        pq.pop();
        if(visited[node]) continue;  //이미 방문한 노드는 넘어간다.
        ans+=dis;             // 추가 되는 가중치 합을 더함 -> 최소 가중치 트리 
        visited[node]=true;
        for(int i=0;i<v[node].size();i++){
            int nextdis=v[node][i].first;
            int nextnode=v[node][i].second;
            if(!visited[nextnode]){
                pq.push({nextdis,nextnode});
            }
        }
    }
}

 

 

 

다익스트라 vs 최소 스패닝 트리 (크루스칼 , 프림)

다익스트라

  • 한 노드에서 다른 노드 한점 까지의 최소 노드를 구하는 것이다.

최소 스패닝 트리

  • 모든 노드에서 가중치 합이 가장 작은 트리를 만드는 것

 

다익스트라 알고리즘 구현 (방문노드 체크는 필요하지 않다 →최소 로 갱신이 필요하기 때문)

void dijkstra(int start){
    dist[start]=0;
    priority_queue<pair<int,int>, vector<pair<int,int>>,greater<pair<int,int>>> q;
    q.push({dist[start],start});
    while(!q.empty()){
        int distNow = q.top().first;
        int node = q.top().second;
        q.pop();
        
        if(dist[node]<distNow) continue;    //방문할 노드 가중치가 현재 가중치보다 작으면 넘어감
        for(int i=0;i<arr[node].size();i++){
            int distNext = arr[node][i].first;
            int nodeNext = arr[node][i].second;
            if( dist[nodeNext]> dist[node]+distNext){
                dist[nodeNext] = dist[node] + distNext;
                q.push({dist[nodeNext],nodeNext});
            }
        }
    }
}