본문 바로가기
카테고리 없음

백준 2211 c++ "네트워크 복구" -PlusUltraCode-

by PlusUltraCode 2025. 10. 30.

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

[필자 사고]

최단거리 루트.. 뭐다?? 다익스트라 알고리즘이다. 다만 이 문제에서 요구하는 거는 역추적

즉 해당 회선 경로까지 추출해야 된다는 점이다.

그래서 필자는 parent를 이용하여 부모노드 까지 기록을 해주었다.

 

아래는 자세한 코드 해설이다.

[코드 해설]

문제 핵심 요약

  • 1번 컴퓨터가 슈퍼컴퓨터.
  • 네트워크를 “최소 개수의 회선”으로 복구하되, 1번에서 각 컴퓨터까지의 최단 통신 시간은 기존과 동일해야 함.
  • 즉, 1번을 루트로 하는 최단경로 트리(Shortest Path Tree, SPT) 를 복구하면 두 조건을 동시에 만족:
    • 트리는 간선 수가 정확히 N-1 → “최소 회선”
    • 다익스트라로 얻은 최단거리 기반 트리 → “최단 시간 유지”

아이디어 한 줄 정리

1번에서 다익스트라를 돌리며 parent[v](v로 가는 최단경로 상의 직전 정점)를 저장.
마지막에 v = 2..N에 대해 (parent[v], v)를 출력하면 된다. 이 간선 집합이 곧 복구해야 할 회선 목록이다.


코드 구조 해설 (제공하신 코드 기준)

그래프 표현

struct Node {
    int value; // 간선 가중치
    int to;    // 도착 정점
};
vector<vector<Node>> arr; // 인접 리스트
  • arr[u]는 정점 u에서 나가는 간선 목록.
  • 각 간선은 (to, value)로 저장.

입력

cin >> N >> M;
arr.resize(N + 1);
for (int i = 0; i < M; i++) {
    int start, end, value;
    cin >> start >> end >> value;
    arr[start].push_back({value, end});
    arr[end].push_back({value, start});
}
  • 양방향 가중치 그래프를 구성.

우선순위 큐(최소 힙) 비교자

struct cmp {
    bool operator()(Node a, Node b) {
        return a.value > b.value;
    }
};
  • value(여기서는 “현재까지의 누적 거리”)가 작은 것이 먼저 나오도록 하는 최소 힙.

다익스트라 핵심(BFS라는 이름이지만 실제로는 다익스트라)

priority_queue<Node, vector<Node>, cmp> pq;
pq.push({0, 1}); // (거리 0, 시작점 1)
vector<int> dist(N + 1, 987654321);
vector<int> parent(N + 1, -1);
dist[1] = 0;

while (!pq.empty()) {
    int value = pq.top().value; // 지금 꺼낸 경로의 누적 거리
    int to    = pq.top().to;    // 지금 위치한 정점
    pq.pop();

    for (Node node : arr[to]) {
        int nextNode  = node.to;
        int nextValue = node.value + value; // to까지의 거리 + (to→nextNode 간선 가중치)

        if (nextValue < dist[nextNode]) {
            dist[nextNode]   = nextValue;
            parent[nextNode] = to;          // 최단경로 상의 직전 정점 갱신
            pq.push({ nextValue, nextNode });
        }
    }
}
  • 전형적인 다익스트라 구현.
  • parent[nextNode] = to로 “최단경로 트리”를 동시에 복원한다.

출력(복구해야 할 회선)

cout << N - 1 << "\n";
for (int v = 2; v <= N; v++) {
    cout << parent[v] << " " << v << "\n";
}
  • 트리의 간선 수는 항상 N-1.
  • 각 노드 v(2..N)에 대해 (parent[v], v)를 출력.
  • 스페셜 저지이므로 순서는 자유롭다.

왜 이것이 정답인가?

  1. 최소 회선: 모든 노드가 통신 가능하려면 그래프가 연결되어야 한다.
    연결 그래프 중 간선 수가 최소인 구조는 트리이며 간선 수는 항상 N-1.
  2. 최단 시간 유지: 1번에서 각 노드까지의 최단 거리를 보존하려면, 각 노드로 가는 최단경로 중에서 간선 하나씩만 선택하면 된다.
    다익스트라의 parent[]가 바로 그 간선들을 가리키므로, 해당 간선들만 복구해도 모든 노드의 최단거리는 기존과 동일하다.

복잡도

  • 시간: O((N + M) log N) (우선순위 큐 사용한 다익스트라 표준)
  • 공간: O(N + M)

구현 팁과 개선 포인트

  • 함수명이 BFS()로 되어 있지만, 실제로는 다익스트라이므로 함수명을 Dijkstra()로 바꾸면 가독성이 좋아진다.
  • 우선순위 큐에서 꺼낸 경로가 **구식(오래된)**일 수 있으므로 아래 한 줄을 넣으면 성능/안정성이 올라간다.
  • if (value != dist[to]) continue; // 최단거리로 갱신된 최신 상태만 진행
  • INF는 상수로 두는 것을 권장:
  • const int INF = 1e9; vector<int> dist(N + 1, INF);
  • 이 문제는 원 그래프에서 1번이 모든 노드에 도달 가능하다는 전제가 사실상 깔려 있다.
    만약 일부 노드가 도달 불가능하다면 parent[v] == -1이 남을 수 있으므로, 실전 코드라면 이 경우를 체크해 별도 처리(예: 도달 가능한 노드만 출력)하는 방어 로직을 둘 수 있다.

예시 입력의 동작 직관

  • 1에서 2,3,4로의 최단거리를 다익스트라로 구한다.
  • 각 노드의 최단경로 직전 정점으로 구성된 간선 집합이 출력 예시처럼 나온다.
  • 출력 간선 수는 항상 N-1이므로 조건 1 충족, 다익스트라의 최단거리 보존으로 조건 2 충족.

 

[소스 코드]

#include <iostream>
#include <vector>
#include <queue>
using namespace std;
struct Node {
	int value;
	int to;
};


int N, M;
vector<vector<Node>> arr;

void Input() {
	cin >> N >> M;
	arr.resize(N + 1);

	for (int i = 0; i < M; i++) {
		int start, end, value;
		cin >> start >> end >> value;
		arr[start].push_back({value,end});
		arr[end].push_back({ value,start });
	}


}

struct cmp {
	bool operator()(Node a, Node b) {
		return a.value > b.value;
	}
};

void BFS() {
	priority_queue<Node, vector<Node>, cmp> pq;
	pq.push({ 0,1 });
	vector<int> dist(N + 1, 987654321);
	vector<int> parent(N + 1, -1);
	dist[1] = 0;
	while (!pq.empty()) {
		int value = pq.top().value;
		int to = pq.top().to;
		pq.pop();

		for (Node node : arr[to]) {
			int nextNode = node.to;
			int nextValue = node.value + value;

			if (nextValue < dist[nextNode]) {
				dist[nextNode] = nextValue;
				pq.push({ nextValue, nextNode });
				parent[nextNode] = to;
			}
		}
	}
	
	cout << N - 1 << "\n";
	for (int v = 2; v <= N; v++) {
		cout << parent[v] << " " << v << "\n";
	}
	
}

void Game_Start() {
	BFS();
	
}

int main(void) {
	Input();
	Game_Start();
}