-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[5월 17일] 트리 #13
base: main
Are you sure you want to change the base?
The head ref may contain hidden characters: "\uD2B8\uB9AC"
[5월 17일] 트리 #13
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// | ||
// [1068] 트리 | ||
// | ||
|
||
#include <iostream> | ||
#include <vector> | ||
|
||
using namespace std; | ||
|
||
// 이차원 벡터로 -> 인덱스가 부모노드, 노드 번호는 벡터로 저장 | ||
vector<vector<int>> tree; | ||
|
||
|
||
// 리프노드 개수 구하는 함수 (현재 루트노드, 삭제할 노드 매개변수) | ||
int dfsLeafNode(int curr, int del) { | ||
// 자신이 곧 삭제될 노드면 -> 0 | ||
if (curr == del) { | ||
return 0; | ||
} | ||
|
||
|
||
// 자식이 없거나 or 자식이 하나로 유일한데 그게 곧 삭제될 노드라면 | ||
if (tree[curr].empty() || tree[curr].size() == 1 && tree[curr][0] == del) { | ||
return 1; | ||
} | ||
|
||
int cnt = 0; | ||
|
||
// 자식노드들 따라 내려가면서 cnt값 갱신 | ||
for (int i = 0; i < tree[curr].size(); i++) { | ||
cnt += dfsLeafNode(tree[curr][i], del); | ||
} | ||
|
||
return cnt; | ||
} | ||
|
||
|
||
int main() { | ||
int n, node, del, root; | ||
|
||
cin >> n; | ||
|
||
// bool형보다는 int형으로! | ||
tree.assign(n, vector<int>(0)); | ||
|
||
// 입력 받기 | ||
for (int i = 0; i < n; i++) { | ||
cin >> node; | ||
|
||
// 루트노드 root에 저장! | ||
if (node == -1) { | ||
root = i; | ||
continue; | ||
} | ||
// 부모 노드가 node이고, i를 자식으로 넣어주기 | ||
else { | ||
tree[node].push_back(i); | ||
} | ||
} | ||
|
||
cin >> del; | ||
|
||
cout << dfsLeafNode(root, del); | ||
|
||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
#include <iostream> // 표준입출력 헤더 | ||
#include <vector> // 벡터 헤더 | ||
|
||
using namespace std; | ||
|
||
// subtree 개수 세기 -> 루트 번호에 대해, subtree 개수 저장 | ||
vector<int> subtree_cnt; | ||
|
||
// 루트 번호, graph 벡터를 매개변수로 | ||
int treeDp(int cur, vector<vector<int>>& graph) { | ||
if (subtree_cnt[cur] != -1) { //이미 탐색했던 상태 | ||
// 바로 현재 루트에 대해 subtree_cnt 리턴 | ||
return subtree_cnt[cur]; | ||
} | ||
|
||
//서브트리에 속한 정점의 수를 세고, 저장 | ||
subtree_cnt[cur] = 0; | ||
|
||
// 루트노드 1개는 항상 포함이므로 노드 개수 1로 지정 | ||
int node = 1; | ||
|
||
// 현재 노드에서 연결된 자식노드들에 대해 | ||
for (int i = 0; i < graph[cur].size(); i++) { | ||
// treeDp 연산 해서 node 결과에 갱신시켜주기 | ||
node += treeDp(graph[cur][i], graph); | ||
} | ||
|
||
// 현재 subtree_cnt는 node로 저장되어 리턴 | ||
return subtree_cnt[cur] = node; | ||
} | ||
|
||
/** | ||
* PPT 트리의 정점의 수 구하기 응용 | ||
* | ||
* [트리와 쿼리] | ||
* | ||
* 1. 루트에서부터 dfs 탐색 | ||
* 2. 각 노드를 루트로 하는 서브트리의 정점 수를 재귀적으로 메모리제이션하며 계산 | ||
* - 서브트리에 속한 정점의 개수를 저장하는 dp 배열의 초기화를 -1로 해주고, | ||
* dfs 탐색 시 현재 정점의 dp 값을 0으로 설정함으로써 자식 노드만 탐색할 수 있도록 함 (부모 노드에 0이 저장되어 있으므로 바로 리턴) | ||
* | ||
*/ | ||
|
||
int main() { | ||
// 입출력 속도 향상 | ||
ios::sync_with_stdio(false); | ||
cin.tie(NULL); | ||
|
||
// 정점 개수, 루트번호, 쿼리 수, u-v 간선 정보(방향x), | ||
int n, r, q, u, v, input; | ||
|
||
//입력 | ||
cin >> n >> r >> q; | ||
|
||
// 이차원벡터 선언 | ||
vector<vector<int>> graph(n + 1, vector<int>(0)); | ||
|
||
// 모든 노드들에 대해 일단 subtree에 속한 정점 개수 -1로 초기화 | ||
subtree_cnt.assign(n + 1, -1); | ||
|
||
|
||
// n-1회 반복 | ||
while (--n) { //무방향 그래프 | ||
// 간선 정보 | ||
cin >> u >> v; | ||
|
||
// 무방향이므로 각각 u,v에 대해 push_back 해줘야 | ||
graph[u].push_back(v); | ||
graph[v].push_back(u); | ||
} | ||
|
||
//연산 | ||
treeDp(r, graph); | ||
|
||
//출력 (쿼리 개수 q만큼 반복) | ||
while (q--) { | ||
// 입력 받고 | ||
cin >> input; | ||
|
||
// input을 루트 노드로 하는 subtree_cnt 개수 출력 | ||
cout << subtree_cnt[input] << '\n'; | ||
} | ||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#include <iostream> // 표준 입출력 헤더 | ||
#include <vector> // 벡터 헤더 파일 | ||
#include <map> // 맵 헤더 파일 | ||
#include <algorithm> // 알고리즘 헤더 파일 -> min_element | ||
|
||
using namespace std; | ||
|
||
// pair형 이름 지정 | ||
typedef pair<int, int> ci; | ||
|
||
|
||
// 비교함수 (min_element용) | ||
bool cmp(const pair<int, ci>& c1, const pair<int, ci>& c2) { | ||
// 후보자들의 추천횟수가 다르면 | ||
if (c1.second.first != c2.second.first) { | ||
// 추천 횟수가 작은 걸 삭제 | ||
return c1.second.first < c2.second.first; | ||
} | ||
|
||
// 게시 시간이 더 오래된 걸 삭제 | ||
return c1.second.second < c2.second.second; | ||
} | ||
|
||
/** | ||
* [후보 추천하기] | ||
* | ||
* 1. 비어있는 사진틀이 없는 경우, 가장 추천수가 작은 학생 중 게시 시간이 오래된 학생을 삭제 | ||
* -> min_element() 함수를 활용해서 조건을 만족하는 학생 찾기 | ||
* -> min_element(x.begin(), x.end(), cmp): x 컨테이너 내에서 최솟값을 찾아주는 함수로 정렬과 비슷하게 cmp함수 써서 조건 설정 가능! | ||
* | ||
* 2. 후보 학생을 바로 찾기 위해 본 풀이는 map 컨테이너를 사용해 구현 | ||
* | ||
* !주의! 게시 시간 정보 저장 시, 후보로 올라간 가장 첫 시간을 저장. 이미 후보에 있는데 게시 시간이 갱신되지 않도록 주의. | ||
*/ | ||
|
||
int main() { | ||
// 사진틀, 추천횟수, 추천받은 학생 번호 | ||
int n, m, input; | ||
|
||
//입력 & 연산 | ||
cin >> n >> m; | ||
|
||
map<int, ci> candidate; //first: 후보 학생 번호, second: {추천 횟수, 게시 시간} | ||
|
||
// 추천횟수 m만큼 입력받기 | ||
for (int i = 0; i < m; i++) { | ||
// 추천받은 학생 누군지 | ||
cin >> input; | ||
|
||
//비어있는 사진틀이 없는 경우 | ||
// 즉 후보자들이 n명 && 방금 입력받은 후보자가 첫 게시이면 | ||
if (candidate.size() == n && candidate.find(input) == candidate.end()) { | ||
|
||
// min_element 함수 : candidate의 처음부터 끝까지 돌면서 비교함수 cmp 조건에 맞는 후보자를 삭제 | ||
candidate.erase(min_element(candidate.begin(), candidate.end(), cmp)); | ||
} | ||
//첫 게시라면 | ||
if (candidate.find(input) == candidate.end()) { | ||
// 게시 시간 저장 | ||
candidate[input].second = i; | ||
} | ||
candidate[input].first++; //추천 횟수 증가 | ||
} | ||
|
||
//출력 (후보학생 번호) | ||
for (auto iter = candidate.begin(); iter != candidate.end(); iter++) { | ||
// 반복자 이용해서 출력 | ||
cout << iter->first << ' '; | ||
} | ||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#include <iostream> // 표준입출력 헤더 | ||
#include <vector> // 벡터 헤더 | ||
|
||
using namespace std; | ||
|
||
// pair형 선언 | ||
typedef pair<int, int> ci; | ||
|
||
ci dfs(int node, int parent, vector<vector<ci>>& graph) { | ||
int pos = node, len = 0; //지름을 구성하는 노드 중 하나, 그 노드까지의 거리 | ||
for (int i = 0; i < graph[node].size(); i++) { | ||
// 다음 노드 -> 현재 노드의 자식노드로 지정 | ||
int next_node = graph[node][i].first; | ||
// 만약 다음 노드가 매개변수로 주어진 parent이면 다음 반복 | ||
if (next_node == parent) { | ||
continue; | ||
} | ||
|
||
ci dfs_search = dfs(next_node, node, graph); //자식 노드에 대해 dfs 탐색 | ||
if (graph[node][i].second + dfs_search.second > len) { //기존 거리보다 길다면 갱신 | ||
// len 갱신 (지름 길이로), second는 가중치 | ||
len = graph[node][i].second + dfs_search.second; | ||
// pos 갱신 (dfs 탐색 결과 나온 pos로) | ||
pos = dfs_search.first; | ||
} | ||
} | ||
// 노드 하나와 거리 리턴 | ||
return { pos, len }; | ||
} | ||
|
||
/** | ||
* [트리의 지름] | ||
* | ||
* 1. 지름을 이루는 두 점은 모두 리프 노드 | ||
* 2. 임의의 한 노드에서 가장 멀리 있는 노드(리프 노드)는 지름을 이루는 노드 중 하나 | ||
* 3. 지름을 이루는 노드에서 가장 멀리 있는 노드는 지름을 이루는 다른 노드 | ||
* | ||
* 부모->자식의 방향만 저장하면 리프 노드에서 다른 리프 노드로 탐색할 수 없으므로 무방향 그래프로 저장 | ||
*/ | ||
|
||
int main() { | ||
// 노드 개수, 부모노드, 자식노드, 가중치 | ||
int n, p, c, w; | ||
|
||
//입력 | ||
cin >> n; | ||
|
||
// 그래프 벡터로 선언 | ||
vector<vector<ci>> graph(n + 1, vector<ci>(0)); | ||
|
||
// n-1회만큼 간선정보 입력받기 | ||
for (int i = 1; i < n; i++) { //무방향 그래프로 만들기 | ||
// 부모, 자식, 가중치 | ||
cin >> p >> c >> w; | ||
|
||
// 무방향 그래프이므로 p와 c가 연결되어있고 가중치가 w임을 표시 | ||
graph[p].push_back({ c, w }); | ||
graph[c].push_back({ p, w }); | ||
} | ||
|
||
//연산 | ||
ci first_node = dfs(1, -1, graph); //지름을 구성하는 노드 하나 찾기 | ||
ci second_node = dfs(first_node.first, -1, graph); //지름을 구성하는 다른 노드 찾기 | ||
|
||
//출력 (다른 노드의, 거리값) | ||
cout << second_node.second; | ||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// | ||
// [5639] 이진 검색 트리 | ||
// -> 맵 말고 구조체, 포인터 이용해서 트리 생성 !! | ||
|
||
#include <iostream> | ||
|
||
using namespace std; | ||
|
||
// 구조체 : 루트 노드, left, right값 -> 계속 노드로 연결 | ||
struct Node { | ||
int data; | ||
Node* left; | ||
Node* right; | ||
}; | ||
|
||
// 트리 만드는 함수 : 리턴형 void로 하면 까다롭.. | ||
Node* makeTree(Node* tree, int x) { | ||
// 맨 처음거 메인 함수에서 초기화했다고 이 부분 안 넣어주면 안됐음 -> left, right 노드들은 안 채워졌을 거니까! | ||
if (tree == NULL) { | ||
tree = new Node(); | ||
tree->data = x; | ||
tree->left = tree->right = NULL; | ||
} | ||
|
||
// 'else' if.. | ||
else if (x <= tree->data) { | ||
tree->left = makeTree(tree->left, x); | ||
} | ||
else tree->right = makeTree(tree->right, x); | ||
|
||
return tree; | ||
} | ||
|
||
// 후위순회 | ||
void postorder(Node* tree) { | ||
if (tree->left != NULL) { | ||
postorder(tree->left); | ||
} | ||
if (tree->right != NULL) { | ||
postorder(tree->right); | ||
} | ||
|
||
cout << tree->data << '\n'; | ||
} | ||
|
||
|
||
int main() { | ||
int root, x; | ||
|
||
cin >> root; | ||
|
||
// 맨 처음 초기화 -> 루트노드 설정 | ||
Node* tree = new Node(); | ||
tree->data = root; | ||
tree->left = tree->right = NULL; | ||
|
||
// ctrl + z 입력해야 ! | ||
while (cin >> x) { | ||
if (x == EOF) break; | ||
Comment on lines
+58
to
+59
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 입력이 더 이상 주어지지 않을 때 프로그램을 종료하는 방법은 cin.eof()을 쓰는 것과 cin.eof()을 쓰지 않는 방법이 있습니다!
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아아 ctrl+z 를 입력했어야 하는군요ㅜㅜ🥲 감사합니다 !! |
||
|
||
// 계속 트리 갱신 | ||
tree = makeTree(tree, x); | ||
} | ||
|
||
// 후위순회 | ||
postorder(tree); | ||
|
||
return 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥰🥰최고에용🥰🥰!!!