반응형
문제 설명
algospot.com :: FORTRESS
요새 문제 정보 문제 중세의 성과 요새들은 보안을 튼튼히 하면서도 더 넓은 영역을 보호하기 위해 여러 개의 성벽을 갖고 있었다고 하지요. 전세계에서 가장 편집증이 심한 영주가 지은 스트로
www.algospot.com
- 원형의 요새의 정보(x, y, r)이 주어진다.
- 요새는 서로 겹치거나 닿지 않는다.
- 첫번째 주어지는 성벽은 외벽이며, 다른 모든 성벽을 포함한다.
=> 요새 내의 두 지점 간을 이동하기 위해 넘어야하는 성벽의 수의 최대값 출력하기
문제 풀이
요새의 상관관계(?) 분석하기
요새들은 서로 겹치거나 닿지 않는다.
즉 요새들은 다른 요새를 포함하거나, 포함되어있는 상태이다.
이를 트리구조로 표현하면
- 부모 노드 - 넓은 요새
- 자식 노드 - 포함되는 요새
로 표현할 수 있다.
두 요새 간 포함관계를 알기 위해서는 다음 두 조건을 만족해야 한다.
큰 요새를 c1, 작은 요새를 c2라고 한다면,
- c1의 반지름 > c2의 반지름
- c1, c2의 중심간 거리 < c1의 반지름
을 성립하면 c2이 c1에 포함되어있다고 할 수 있다.
이 때, c2의 반지름을 고려하지 않는 이유는 문제에서 요새끼리는 겹치지 않는다는 조건이 있었으므로
두 중심간의 거리가 c1의 반지름보다 작으면 무조건 포함하는 상태임을 확인할 수 있다.
위의 조건을 만족하는지 확인하며 요새간의 관계를 트리구조로 정의하자.
최대 성벽의 수 구하기
두 지점에서 넘어야 하는 최대 성벽의 수는 트리구조로 표현된 요새간의 관계에서
한 노드에서 다른 노드로 향하는 간선의 수가 가장 많은 경우를 출력하면 된다.
간선의 수가 가장 많으려면,
- 루트 노드에서 리프 노드
- 리프 노드에서 또 다른 리프 노드
의 두 가지 경우가 가장 간선이 많을 수 있는 경우이다.
이 경우들을 BFS를 이용해 전부 탐색하고, 최대 간선의 개수를 출력하자.
문제 풀이 코드
#include <iostream>
#include <algorithm>
#include <queue>
#define MAX(a,b)(a > b ? a : b)
using namespace std;
struct Node {
int x, y, r, parentIdx, childrenCnt = 0;
int children[100];
};
Node nodes[100];
double dists[100][100];
bool isEnd[100];
int dist = 0;
double getDist(int i, int j) { // 중심간 거리 구하기
return sqrt(pow(nodes[i].x - nodes[j].x, 2) + pow(nodes[i].y - nodes[j].y, 2));
}
int findParent(int idx) { // 부모 노드 찾기
int parent = 0;
bool findParent = true;
while (findParent) {
findParent = false;
for (int i = 0; i < nodes[parent].childrenCnt; ++i) {
int parentIdx = nodes[parent].children[i];
if (nodes[parentIdx].r > nodes[idx].r && nodes[parentIdx].r > dists[parentIdx][idx]) {
parent = parentIdx;
findParent = true;
break;
}
}
}
return parent;
}
bool compare_Node(const Node& node1, const Node& node2) { // 비교 함수
return node1.r > node2.r;
}
void doBFS(int idx) { // idx부터 다른 끝점간의 간선수 구하기
bool visited[100];
fill_n(visited, 100, false);
queue<int> q;
q.push(idx);
int length = 0;
while (!q.empty()) {
int size = q.size();
while (--size >= 0) {
int i = q.front();
q.pop();
if (visited[i])
continue;
visited[i] = true;
if (isEnd[i]) {
dist = MAX(dist, length);
}
if (nodes[i].parentIdx != -1)
q.push(nodes[i].parentIdx);
for (int j = 0; j < nodes[i].childrenCnt; ++j) {
q.push(nodes[i].children[j]);
}
}
++length;
}
}
void init() { // 초기화
dist = 0;
fill_n(isEnd, 100, true);
for (int i = 0; i < 100; ++i) {
nodes[i].x = 0;
nodes[i].y = 0;
nodes[i].r = 0;
nodes[i].parentIdx = 0;
nodes[i].childrenCnt = 0;
}
}
int main() {
int C;
cin >> C;
for (int tc = 1; tc <= C; ++tc) {
init();
int N;
cin >> N;
cin >> nodes[0].x >> nodes[0].y >> nodes[0].r;
nodes[0].parentIdx = -1;
for (int i = 1; i < N; ++i) {
cin >> nodes[i].x >> nodes[i].y >> nodes[i].r;
}
// 반지름 내림차순으로 정렬하기
sort(nodes, nodes + 100, &compare_Node);
// 중심간 거리 구하기
for (int i = 1; i < N; ++i) {
for (int j = 0; j < i; ++j) {
dists[i][j] = dists[j][i] = getDist(i, j);
}
}
// 부모, 자식 노드 찾기
for (int i = 1; i < N; ++i) {
int parent = findParent(i);
isEnd[parent] = false; // 자식이 존재한다 == 리프 노드가 아니다.
nodes[parent].children[nodes[parent].childrenCnt++] = i;
nodes[i].parentIdx = parent;
}
isEnd[0] = true;
// 끝점간의 간선수 구하기
for (int i = 0; i < N; ++i) {
if (isEnd[i])
doBFS(i);
}
cout << dist << endl;
}
return 0;
}
반응형
'알고리즘 문제풀이 > 알고리즘 문제해결전략' 카테고리의 다른 글
23.3_변화하는 중간값_RUNNINGMEDIAN (0) | 2023.07.21 |
---|---|
21.3_트리 순회 순서 변경_TRAVERSAL (0) | 2023.06.02 |
19.6_외계 신호 분석_ITES (2) | 2023.05.10 |
19.4_짝이 맞지 않는 괄호_BRACKETS2 (0) | 2023.05.03 |
18.5_조세푸스 문제_JOSEPHUS (0) | 2023.04.25 |