Algorithm/Brutal Force

[완전탐색] 송전탑 수 확인

Maison 2025. 1. 6. 16:57

문제

 

송전탑의 개수 n, 그리고 전선 정보 wires가 매개변수로 주어집니다. 
전선들 중 하나를 끊어서 송전탑 개수가 가능한 비슷하도록 두 전력망으로 나누었을 때, 
두 전력망이 가지고 있는 송전탑 개수의 차이(절대값)를 return 하도록 solution 함수를 완성해주세요.

접근

 

1) 출력


- 두 전력망이 가지고 있는 송전탑 개수의 차이(절대값)

2) 개념화

문제의 해 : 두 전력망이 가지고 있는 송전탑 개수의 차이(절대값)

- 모든 경우의수를 확인하여 두개의 트리의 수가 적은 값을 도출해내야함.

1. 트리 연결 확인
2. 연결된 엣지를 하나씩 끊기.
 - 연결된 엣지 : wire 배열.

3. 엣지를 끊었을 때 두 서브트리들의 노드 차이 계산
 - 각 서브트리들 간 노드의 수 파악법 ? //BFS로 확인 가능/
4. 노드 차이를 벡터에 넣기.
5. 벡터에서 가장 작은 값 도출.

3) 구현

BFS 사용.

1) 전체 wire수만큼 반복.
2) wire[n] 끊기. sub grpah1 = wire[0][0]부터 bfs // sub graph2 = wire[0][1] 부터 bfs.
3) 두 그래프를 돌아가며 count 증가시키기.
4) 두 count 간의 차를 구하여 벡터이 인가.

 

코드

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <unordered_map>

using namespace std;

// 각 sub node의 수 계산 후 리턴.
int cal_nodecnt(vector<vector<int>> wire,int node)
{
    int num=1;
    queue<int> q;// bfs로 순회시 연결된 노드 추가.
    // vector<int> visited(wire.size()+1,0);// vector로 사용하니 너무 많은 값을 사용해야함. 따라서 map사용하는게 나을듯.
    unordered_map<int,bool> visited;
    for(int i=0;i<wire.size();i++)
    {
        visited[wire[i][0]]=false;
        visited[wire[i][1]]=false;
    }

    q.push(node);

    while(!q.empty())
    {
        int cur_node = q.front();
        q.pop();

        if(visited[cur_node]==false)
            visited[cur_node]=true;
        else
            continue;

        for(auto edge : wire)
        {
            if((edge[0]==cur_node&&visited[edge[1]]==false))
            {
                q.push(edge[1]);
                num++;
            }
            else if(edge[1]==cur_node&&visited[edge[0]]==false)
            {
                q.push(edge[0]);
                num++;
            }
        }
    }

    return num;
}


int solution(int n,vector<vector<int>> wire)
{
    int answer;
    set<int> res;
    for (int i = 0; i < wire.size(); i++)
    {
        int nd_1 = wire[i][0];
        int nd_2 = wire[i][1];
        vector<vector<int>> sub_wire=wire;
        sub_wire.erase(sub_wire.begin() +i);

        int nd1_num = cal_nodecnt(sub_wire,nd_1);
        int nd2_num = cal_nodecnt(sub_wire,nd_2);

        res.insert(abs(nd1_num-nd2_num));
    }

    answer = *min_element(res.begin(),res.end());
    return answer;
}
/*
입출력 예
n	wires	result
9	[[1,3],[2,3],[3,4],[4,5],[4,6],[4,7],[7,8],[7,9]]	3
4	[[1,2],[2,3],[3,4]]	0
7	[[1,2],[2,7],[3,7],[3,4],[4,5],[6,7]]	1

*/
int main()
{
    vector<vector<int>> wire1 {{1,3},{2,3},{3,4},{4,5},{4,6},{4,7},{7,8},{7,9}};
    vector<vector<int>> wire2 {{1,2},{2,3},{3,4}};
    vector<vector<int>> wire3 {{1,2},{2,7},{3,7},{3,4},{4,5},{6,7}};

    cout<<solution(wire1);
    cout<<solution(wire2);
    cout<<solution(wire3);
}

 

 

* 알게 된 내용

 

1) 개념 부족 

 - 개념은 각 node별 BFS 순회를 진행하여 sub graph의 node 수를 구하기로 했음.

 - 그렇게 하기 위해선 현재 노드의 방문 가능한 인접 노드들을 구하고, 해당 인접 node를 queue에 인가해야함.

 - 인접 노드를 구하는 방식, edge 배열을 순회하여 현재 노드와 인접한 노드를 구하고, 해당 노드에 방문한적이 없어야함.

 

비교 

 => 문제는 edge의[0]이 현재노드일때만 비교하여 전체 경우의 수를 비교하지 못한것.

 => edge의 [0],[1] 모두가 현재 노드일때 상대 원소가 visited 되었는지 확인하고 진행해야함.

 

* 정리

[개념 잡기.]

-> node 기준, edge 배열을 사용하여 인접 node를 구하여, sub graph의 수를 구한다.

-> edge 배열은 순번에 상관있기때문에 배열의 순서에 상관없이 모두 비교 진행해야한다.

 

 

2) erase 메서드

erase 메서드는 반복자를 매개변수로 받는다.

따라서 반복자를 넣어줘야한다.

 

ex) VECTOR.erase(VECTOR.begin())

      VECTOR.erase(find(VECTOR.begin(),VECTOR.end(),erase_component))

 

 

3) set에서의 데이터 접근

 

set은 리스트로 구성되어있기 때문에 인덱스로 원소에 접근이 불가능하다.

따라서 각 원소들의 반복자들에 *연산자를 사용하여 값을 불러올 수 있다.