baekjoon

[백준] 2660 회장뽑기 (복습) + 큐를 사용하는 두가지 방법

윤만석 2022. 12. 27. 13:02
문제

월드컵 축구의 응원을 위한 모임에서 회장을 선출하려고 한다. 이 모임은 만들어진지 얼마 되지 않았기 때문에 회원 사이에 서로 모르는 사람도 있지만, 몇 사람을 통하면 모두가 서로 알 수 있다. 각 회원은 다른 회원들과 가까운 정도에 따라 점수를 받게 된다.

예를 들어 어느 회원이 다른 모든 회원과 친구이면, 이 회원의 점수는 1점이다. 어느 회원의 점수가 2점이면, 다른 모든 회원이 친구이거나 친구의 친구임을 말한다. 또한 어느 회원의 점수가 3점이면, 다른 모든 회원이 친구이거나, 친구의 친구이거나, 친구의 친구의 친구임을 말한다.

4점, 5점 등은 같은 방법으로 정해진다. 각 회원의 점수를 정할 때 주의할 점은 어떤 두 회원이 친구사이이면서 동시에 친구의 친구사이이면, 이 두사람은 친구사이라고 본다.

회장은 회원들 중에서 점수가 가장 작은 사람이 된다. 회장의 점수와 회장이 될 수 있는 모든 사람을 찾는 프로그램을 작성하시오.

입력

입력의 첫째 줄에는 회원의 수가 있다. 단, 회원의 수는 50명을 넘지 않는다. 둘째 줄 이후로는 한 줄에 두 개의 회원번호가 있는데, 이것은 두 회원이 서로 친구임을 나타낸다. 회원번호는 1부터 회원의 수만큼 붙어 있다. 마지막 줄에는 -1이 두 개 들어있다.

출력

첫째 줄에는 회장 후보의 점수와 후보의 수를 출력하고, 두 번째 줄에는 회장 후보를 오름차순으로 모두 출력한다.

 

몇다리 건너 친구가 있는지, 그 다리의 최솟값을 가지는 후보자를 찾는 문제입니다.

한 사람이 정점일 때, 친구 관계는 정점과 정점을 잇고, 그 비용이 모두 같으므로 BFS를 사용할 수 있습니다.

 

그리고 두가지 방법으로 풀어봤습니다.

 

첫번째로는 친구 관계를 저장하기 위해 인접리스트를 사용하고 , C++ STL queue를 사용했습니다.

#include <bits/stdc++.h>
using namespace std;
int v[51];
vector<int> adj[51];
vector<int>answer;
int ans[51];
int n, a, b, num = INT_MAX;

int bfs(int k) {
    queue<int>q;
    q.push(k);
    v[k] = 1;
    int ret = 0;

    while (!q.empty()) {
        auto top = q.front();
        q.pop();
        
        for (auto r : adj[top]) {
            if (!v[r]) {
                v[r] = v[top] + 1;
                ret = max(ret, v[r]);
                q.push(r);
            }
        }
    }
    return ret;
}
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    cin >> n;
    while (1) {
        cin >> a >> b;
        if (a == -1 && b == -1)break;
        adj[a].push_back(b);
        adj[b].push_back(a);
    }
    for (int i = 1; i <= n; i++) {
        memset(v, 0, sizeof(v));
        ans[i] = bfs(i);
        num = min(num, ans[i]);
    }
    for (int i = 1; i <= n; i++) {
        if (num == ans[i]) {
            answer.push_back(i);
        }
    }
    cout << num-1 << " " << answer.size() << "\n";
    for (int r : answer) {
        cout << r << " ";
    }
}

 

두번째로는 친구 관계를 저장할 2차원 배열을 사용했고, 1차원 배열에서 투포인터로 큐를 구현했습니다.

#include<bits/stdc++.h>
using namespace std;

int arr[51][51], q[51], v[51], ans[51];

int main() {
	int i, j, a, b, c, f, r, top;
	int num = 60, idx, n;
	cin >> n;
	while (1) {
		cin >> a >> b;
		if (a < 0)break;
		arr[a][b] = arr[b][a] = 1;  //a랑 b는 친구
	}
	for (int i = 1; i <= n; i++) { //bfs를 n번 수행
		memset(v, 0, sizeof(v));
		v[i] = 1;
		q[f = 0] = i; r = 1;
		while (f < r) {
			top = q[f++]; //팝
			for (int j = 1; j <= n; j++) {
				if (arr[top][j] && !v[j]) { //만약 top과 j가 친구이고 ,j가 미방문이라면
					v[j] = v[top] + 1; //방문처리
					q[r++] = j; //push
				}
			}
		}
		//f==r이면 큐가 비어있다는 의미이므로, 마지막 데이터는 r-1 or f-1에 저장되어있음 그리고 v[r-1]이 가장 큰 값임을 보장받음
		if (v[q[r-1]] < num) { //갱신
			num = v[q[r-1]];
			ans[idx = 1] = i; //idx는 사람수
		}
		else if (v[q[r - 1]] == num) {
			ans[++idx] = i;
		}
	}
	cout << num-1 << " " << idx << "\n";
	for (int i = 1; i <= idx; i++) {
		cout << ans[i] << " ";
	}
}