문제링크 : https://www.acmicpc.net/problem/21278
21278번: 호석이 두 마리 치킨
위의 그림과 같이 1번과 2번 건물에 치킨집을 짓게 되면 1번부터 5번 건물에 대해 치킨집까지의 왕복 시간이 0, 0, 2, 2, 2 로 최소가 된다. 2번과 3번 건물에 지어도 동일한 왕복 시간이 나오지만 더
www.acmicpc.net
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MAX = 987654321;
int N, M;
int dp[101][101];
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> N >> M;
for(int i=1; i<=N; i++)
{
for(int j=1; j<=N; j++)
{
if(i==j) continue; //자기자신 제외
dp[i][j] = MAX;
}
}
for(int i=0; i<M; i++)
{
int x, y;
cin >> x >> y;
dp[x][y]=1; //양방향, 걸리는 시간 1
dp[y][x]=1;
}
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];
}
}
}
}
tuple<int, int, int> result = make_tuple(MAX, MAX, MAX); //건물번호 1, 2, 시간합
for (int i = 1; i <= N; i++) //치킨집 1
{
for (int j = i + 1; j <= N; j++) //치킨집 2
{
int sum = 0;
for (int k = 1; k <= N; k++) //건물
{
sum += min(dp[k][i] * 2, dp[k][j] * 2); //짧은 왕복거리 총합 저장
}
if (get<2>(result) > sum) //최소 거리 및 거리에 대한 위치 갱신
{
result = make_tuple(i, j, sum);
}
}
}
cout << get<0>(result) << " " << get<1>(result) << " " << get<2>(result);
return 0;
}
플로이드 워셜을 이용한 문제이다.
먼저 입력받은 값에 대해 걸리는 시간이 1이고, 양방향 이동이 가능하기에 각 방향에 대 1로 초기화를 해준다.
이후 플로이드 워셜 알고리즘을 이용해 최단거리를 구해준다.
N의 크기가 100밖에 되지않기 때문에 3중 for문을 사용한 플로이드 워셜 알고리즘의 사용이 가능하다.
그 다음에 바로 튜플을 선언해주는데, 이는 건물번호 2개와 해당 건물번호에 대한 왕복시간합을 저장하기 위함이다.
이후 다시 3중 반복문을 사용하는데 i와 j은 치킨집 1, 2 k는 현재 건물이다.
현재 지정한 치킨집 2개를 기준으로 건물을 옮겨가며 걸리는 시간이 더 짧은 건물을 선택한다.
이때 시간은 왕복시간을 재야하므로 *2를 하여 합에 더해준다.
이렇게 더한 합이 현재 고른 치킨집을 기준으로 한 모든 도시에서의 왕복 시간의 합이 된다.
이제 이 합이 최소가 되어야 하므로 tuple에서 선언했던 맨 마지막 값을 이용하여 최소값을 갱신해준다.
치킨집을 옮겨가며 모든 경우에 대해 위의 탐색을 반복해주고, 합이 제일 작을 때의 치킨집 위치와 합을 tuple에 넣어주고 이 tuple 값을 출력해주면 된다.
'백준 > 골드' 카테고리의 다른 글
[백준 1889번] 선물 교환 (C++) (0) | 2023.12.16 |
---|---|
[백준 22856번] 트리 순회 (C++) (0) | 2023.12.14 |
[백준 2643번] 색종이 올려 놓기 (C++) (0) | 2023.12.09 |
[백준 13325번] 이진 트리 (C++) (0) | 2023.12.07 |
[백준 1695번] 팰린드롬 만들기 (C++) (0) | 2023.12.05 |