Skip to content
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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions [5월 17일] 트리/1068.cpp
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;
}
84 changes: 84 additions & 0 deletions [5월 17일] 트리/15681.cpp
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;
}
71 changes: 71 additions & 0 deletions [5월 17일] 트리/1713.cpp
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;
}
68 changes: 68 additions & 0 deletions [5월 17일] 트리/1967.cpp
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;
}
69 changes: 69 additions & 0 deletions [5월 17일] 트리/5639.cpp
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;
}
Comment on lines +18 to +23

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥰🥰최고에용🥰🥰!!!


// '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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

입력이 더 이상 주어지지 않을 때 프로그램을 종료하는 방법은 cin.eof()을 쓰는 것과 cin.eof()을 쓰지 않는 방법이 있습니다!

  • cin.eof() 쓰는 방법
    cin.eof() 은 bool타입을 가집니다! 만약 EOF(파일의 끝을 의미)을 읽게 되면 true로 바뀌게 됩니다. 그래서 보통 while (!cin.eof()) {cin >> n;} 이렇게 많이 쓰이죠! EOF는 콘솔 창에 수동으로 넣어주어야 하며, 윈도우 기준으로 ctrl+z 이 EOF 입니다!
  • cin.eof() 안 쓰는 방법
    그런데 while (cin >> x){...} 처럼 while 문의 조건문 안에 넣어버려도 됩니다! 이는 유효한 값이 들어올 때까지, ctrl+z 되기 전까지 계속 입력을 할 수 있습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아아 ctrl+z 를 입력했어야 하는군요ㅜㅜ🥲 감사합니다 !!


// 계속 트리 갱신
tree = makeTree(tree, x);
}

// 후위순회
postorder(tree);

return 0;
}
Loading