알고리즘/알고리즘 문제 해결전략(종만북)
21장 요새 FORTRESS
pureworld
2018. 12. 28. 22:17
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | #include<iostream> #include<string> #include<vector> #include<cassert> #include<algorithm> #include<queue> #include<functional> #include<random> using namespace std; struct TreeNode { vector<TreeNode*> children; }; //지금까지 찾은 가장 긴 잎-잎의 경로의 길이를 저장. int longest; //입력 데이터 int n, y[100], x[100], radius[100]; //x^2를 반환 int sqr(int x) { return x * x; } int sqrdist(int a, int b) { return sqr(y[a] - y[b]) + sqr(x[a] - x[b]); } //성벽 a가 성벽 b를 포함하는지 확인한다. bool encloses(int a, int b) { //원을 포함하는 걸 확인 하는 공식 (x1-x2)^2+(y1-y2)^2<(r1-r2) return radius[a] > radius[b] && sqrdist(a, b) < sqr(radius[a] - radius[b]); } //'성벽' 트리에서 parent가 child의 부모인지 확인한다. //parent는 child를 꼭 직접 포함해야 한다. bool isChild(int parent, int child) { if (!encloses(parent, child)) return false; for (int i = 0; i < n; i++) { //parent에포함된 원 i, 원 i에 포함된 원 child의 관계가 성립되면 //직접포함관계가 아니라 간접포함관계이므로 false를 return 한다. if (i!=parent && i != child && encloses(parent, i) && encloses(i, child)) return false; } return true; } //root를 루트로 하는 서브트리의 높이를 반환한다. int height(TreeNode* root) { vector<int> heights; for (int i = 0; i < root->children.size(); i++) heights.push_back(height(root->children[i])); //만약 자식이 하나도 없다면 0을 반환. if (heights.empty()) return 0; sort(heights.begin(), heights.end()); //정렬했으므로 heights[heights.size() - 2](2번째로 큰 높이) heights[heights.size() - 1](1번째로 큰 높이) if (heights.size() >= 2) longest = max(longest, 2 + heights[heights.size() - 2] + heights[heights.size() - 1]); //트리의 높이는 서브트리 높이의 최대치에 1을 더해 계산한다. return heights.back() + 1; } int solve(TreeNode* root) { longest = 0; //트리의 높이와 최대 잎-잎 경로 길이 중 큰 것을 선택한다. int h = height(root); return max(longest, h); } TreeNode* getTree(int root) { TreeNode* ret = new TreeNode(); for (int ch = 0; ch < n; ch++) //ch 성벽이 root성벽에 직접적으로 포함되어 있다면 //트리를 만들고 자손 목록에 추가한다. if (isChild(root, ch)) ret->children.push_back(getTree(ch)); return ret; } int main(void) { int cases; cin >> cases; while (cases--) { cin >> n; for (int i = 0; i < n; i++) cin >> x[i] >> y[i] >> radius[i]; TreeNode* root = getTree(0); cout << solve(root) << endl; } return 0; } | cs |
문제 출처:https://algospot.com/judge/problem/read/FORTRESS
책 표기에는 난이도가 중이라고 되어있지만 정말 해결하기 힘든 문제였다. 문제해결방법은 떠올릴 수 있었으나 (그래서 난이도가 중??)
그것을 이렇게 언어로 구현하는 것 자체가 매우 어려워서 실패했다.
본인은 처음 문제를 풀으려고 시도했을때
struct circle{
int x;
int y;
int radius;
};
라는 구조체를 만들어서 한번에 함수에 모든 정보를 다 보내려고 했었는데, 일단 책의 함수와 똑같이 구현하는 방법을
더 연습해보고 처음 시도했던 저 방법으로 다시 구현해보고 코딩내용을 추가 수정해봐야겠다...
문제를 봤을때 대충 어떻게 접근해야 하는지 감이 잡혔으나 도저히 구현할 수 가 없었다.
그리고 최장 경로의 길이가 두가지 경우가 있음에도 본인은 2번의 경우밖에 떠올리지 못했다.
1.가장 긴 루트-잎 경로의 길이
2.가장 긴 잎-잎 경로의 길이
1번의 예외를 놓치기 쉬울 것 같다. 조심하자.