문제 링크
https://www.acmicpc.net/problem/21278
문제
컴공 출신은 치킨집을 하게 되어있다. 현실을 부정하지 말고 받아들이면 마음이 편하다. 결국 호석이도 2050년에는 치킨집을 하고 있다. 치킨집 이름은 "호석이 두마리 치킨"이다.
이번에 키친 도시로 분점을 확보하게 된 호석이 두마리 치킨은 도시 안에 2개의 매장을 지으려고 한다. 도시는 N 개의 건물과 M 개의 도로로 이루어져 있다. 건물은 1번부터 N번의 번호를 가지고 있다. i 번째 도로는 서로 다른 두 건물 Ai 번과 Bi 번 사이를 1 시간에 양방향으로 이동할 수 있는 도로이다.
키친 도시에서 2개의 건물을 골라서 치킨집을 열려고 한다. 이 때 아무 곳이나 열 순 없어서 모든 건물에서의 접근성의 합을 최소화하려고 한다. 건물 X 의 접근성은 X 에서 가장 가까운 호석이 두마리 치킨집까지 왕복하는 최단 시간이다. 즉, "모든 건물에서 가장 가까운 치킨집까지 왕복하는 최단 시간의 총합"을 최소화할 수 있는 건물 2개를 골라서 치킨집을 열려고 하는 것이다.
컴공을 졸업한 지 30년이 넘어가는 호석이는 이제 코딩으로 이 문제를 해결할 줄 모른다. 알고리즘 퇴물 호석이를 위해서 최적의 위치가 될 수 있는 건물 2개의 번호와 그 때의 "모든 건물에서 가장 가까운 치킨집까지 왕복하는 최단 시간의 총합"을 출력하자. 만약 이러한 건물 조합이 여러 개라면, 건물 번호 중 작은 게 더 작을수록, 작은 번호가 같다면 큰 번호가 더 작을수록 좋은 건물 조합이다.
입력
첫 번째 줄에 건물의 개수 N과 도로의 개수 M 이 주어진다. 이어서 M 개의 줄에 걸쳐서 도로의 정보 Ai , Bi 가 공백으로 나뉘어서 주어진다. 같은 도로가 중복되어 주어지는 경우는 없다. 어떤 두 건물을 잡아도 도로를 따라서 오고 가는 방법이 존재함이 보장된다.
출력
한 줄에 건물 2개가 지어질 건물 번호를 오름차순으로 출력하고, 그때 모든 도시에서의 왕복 시간의 합을 출력한다.
만약 건물 조합이 다양하게 가능하면, 작은 번호가 더 작은 것을, 작은 번호가 같다면 큰 번호가 더 작은 걸 출력한다.
제한
- 2 ≤ N ≤ 100
- N-1 ≤ M ≤ N×(N - 1)/2
- 1 ≤ Ai , Bi ≤ N (Ai ≠ Bi)
예제 입력 1
5 4
1 3
4 2
2 5
3 2
예제 출력 1
1 2 6
위의 그림과 같이 1번과 2번 건물에 치킨집을 짓게 되면 1번부터 5번 건물에 대해 치킨집까지의 왕복 시간이 0, 0, 2, 2, 2 로 최소가 된다. 2번과 3번 건물에 지어도 동일한 왕복 시간이 나오지만 더 작은 건물 번호를 출력해야 함을 유의하자.
알고리즘 분류
- 최단 거리 알고리즘
- 브루트포스 알고리즘
풀이
주어진 정보와 플로이드-와샬 알고리즘을 이용하여 최단 거리를 구한다.
그리고 브루트포스를 활용하여, N개의 건물 중 2개를 치킨집으로 정하고 각 건물에서 치킨집까지의 거리의 합의 최솟값과 그 때의 치킨집 두 곳을 구한다.
코드
#include <iostream>
#include <string>
#include <cmath>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#include <climits>
#define FIRST cin.tie(NULL); cout.tie(NULL); ios::sync_with_stdio(false);
#define MAX 101
#define LL long long
#define INF 1e9
using namespace std;
int N, M;
int DP[MAX][MAX];
int answerT = INF;
pair<int, int> answerP;
void init() {
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
if (i == j) {
continue;
}
DP[i][j] = INF;
}
}
for (int i = 0; i < M; i++) {
int A, B;
cin >> A >> B;
DP[A][B] = 1;
DP[B][A] = 1;
}
}
void Settings() {
for (int k = 1; k <= N; k++) {
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
if (DP[i][j] > DP[i][k] + DP[k][j]) {
DP[i][j] = DP[i][k] + DP[k][j];
}
}
}
}
}
void Find_Answer() {
for (int i = 1; i <= N; i++) {
for (int j = i + 1; j <= N; j++) {
int Time_Sum = 0;
for (int k = 1; k <= N; k++) {
Time_Sum += min(DP[k][i] * 2, DP[k][j] * 2);
}
if (answerT > Time_Sum) {
answerT = Time_Sum;
answerP = make_pair(i, j);
}
}
}
}
int main() {
FIRST
cin >> N >> M;
init();
Settings();
Find_Answer();
cout << answerP.first << " " << answerP.second << " " << answerT << "\n";
return 0;
}
'BOJ > Gold' 카테고리의 다른 글
[BOJ/Gold 4] 백준 13424 비밀 모임(C++) (0) | 2022.02.16 |
---|---|
[BOJ/Gold 4] 백준 1719 택배(C++) (0) | 2022.02.16 |
[BOJ/Gold 5] 백준 16958 텔레포트(C++) (0) | 2022.02.15 |
[BOJ/Gold 5] 백준 2660 회장뽑기(C++) (0) | 2022.02.14 |
[BOJ/Gold 1] 백준 17071 숨바꼭질 5(C++) (0) | 2022.02.11 |