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

[최소 신장 트리] 12월 6일 #24

Open
wants to merge 2 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
68 changes: 68 additions & 0 deletions 11월 30일 - 최소 신장 트리/1368.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include <iostream>
#include <vector>
#include <queue>

using namespace std;

//MST (프림)

const double INF = 1e5 + 1;
typedef pair<int, int> ci;

int prim(int v, int start, vector<vector<ci>> &graph) {
int sum = 0;
vector<int> dist(v, INF); //각 정점까지의 비용
vector<bool> visited(v, false); //정점 방문 여부
priority_queue<ci, vector<ci>, greater<>> pq;

dist[start] = 0;
pq.push({ 0, start });

while (!pq.empty()) {
int weight = pq.top().first; //간선 가중치
int node = pq.top().second; //현재 정점
pq.pop();

if (visited[node])
continue;

sum += weight; //MST 간선 가중치 총합
visited[node] = true; //방문 처리

for (int i = 0; i < graph[node].size(); i++) {
int next_weight = graph[node][i].first;
int next_node = graph[node][i].second;
if (!visited[next_node] && next_weight < dist[next_node]) { //미방문 정점 & 더 짧은 간선
dist[next_node] = next_weight;
pq.push({ dist[next_node], next_node });
}
}
}
return sum;
}

int main() {
int n, w, p;

//입력
cin >> n;

vector<vector<ci>> graph(n + 1, vector<ci>(0));
for (int i = 1; i <= n; i++){
cin >> w;
graph[0].emplace_back(w, i);
graph[i].emplace_back(w, 0);
}

for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> p;
if (i != j)
graph[i].emplace_back(p, j);
}
}


//연산 & 출력
cout << prim(n + 1, 0, graph);
}
107 changes: 107 additions & 0 deletions 11월 30일 - 최소 신장 트리/16235.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

//어디가 틀린지 모르겠다.

int dr[] = { -1, -1, -1, 0, 0, 1, 1, 1 };
int dc[] = { -1, 0, 1, -1, 1, -1, 0, 1 };

int n;
vector<int> tree[10][10];
vector<vector<int>> nutrient; //각 위치의 양분 정보
vector<vector<int>> a; //겨울에 추가되는 각 위치의 양분 정보



void grow() {
//봄: 나무가 자신의 나이만큼 양분 먹기(한 칸만) -> 나이 1 증가, 어린나무부터 양분 먹음, 못 먹으면 즉시 죽음
//여름: 죽은 나무 -> 양분, 죽은 나무의 나이를 2로 나눈 값
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (tree[i][j].size() <= 0)
continue;

sort(tree[i][j].begin(), tree[i][j].end());

int summer = 0;
vector<int> alive;
for (int k = 0; k < tree[i][j].size(); k++) {
int age = tree[i][j][k];
if (nutrient[i][j] - age >= 0) {
nutrient[i][j] -= age;
alive.push_back(age++);
}
else {
summer += age / 2;

}
}
nutrient[i][j] += summer;

tree[i][j].clear();
for (int k = 0; k < alive.size(); k++)
tree[i][j].push_back(alive[k]);
}
}

//가을: 나무 번식, 번식 나무는 나이가 5의 배수, 인접한 8칸에 나이 1인 나무 생김.
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (tree[i][j].size() <= 0)
continue;

for (int k = 0; k < tree[i][j].size(); k++) {
int age = tree[i][j][k];
if (age % 5 == 0) {
for (int d = 0; d < 8; d++) {
int nr = i + dr[d], nc = j + dc[d];
if (nr < 0 || nr >= n || nc < 0 || nc >= n)
continue;
tree[nr][nc].push_back(1);
}
}
}
}
}
//겨울: 각 칸에 양분 추가
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
nutrient[i][j] += a[i][j];
}
}

int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);

int m, k, r, c, age;
cin >> n >> m >> k;

nutrient.assign(n, vector<int>(n));
a.assign(n, vector<int>(n));

for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> a[i][j];
nutrient[i][j] = 5;
}
}
for (int i = 0; i < m; i++) {
cin >> r >> c >> age;
tree[r][c].push_back(age);
}
for (int i = 0; i < k; i++) {
grow();
}

int result = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
result += tree[i][j].size();
}
}
cout << result;
}
60 changes: 60 additions & 0 deletions 11월 30일 - 최소 신장 트리/1713.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include <iostream>
#include <map>
#include <queue>

using namespace std;

typedef pair<int, int> ci;

int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);

int n, m, candidate;
cin >> n >> m;
map<int, ci> photo; //{학생 번호, {추천 횟수, 게시 시간}}
int time = 0;

while(m--) {
cin >> candidate;
//이미 게시된 학생이면 추천 횟수만 증가
if (photo.find(candidate) != photo.end()) {
photo[candidate].first++;
}
//아니라면
else {
//비어있는 사진틀이 없으면
if (photo.size() >= n) {
int temp = 1001;
map<int, ci>::iterator erase;

//추천수가 적은 학생 삭제
for (auto iter = photo.begin(); iter != photo.end(); iter++) {
if (temp > iter->second.first) {
temp = iter->second.first;
erase = iter;
}
}

//아니면 오래된 학생 삭제
for (auto iter = photo.begin(); iter != photo.end(); iter++) {
if (temp == iter->second.first) {
if (erase->second.second > iter->second.second)
erase = iter;
}
}
photo.erase(erase);
photo.insert({ candidate, {1, time++} });
}

//비어있는 사진틀이 있으면 그냥 삽입
else {
photo.insert({ candidate, {1, time++} });
}
}
}
for (auto iter = photo.begin(); iter != photo.end(); iter++) {
cout << iter->first << " ";
}
return 0;
}
92 changes: 92 additions & 0 deletions 11월 30일 - 최소 신장 트리/1774.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#include <iostream>
#include <vector>
#include <tuple>
#include <queue>
#include <cmath>

using namespace std;

//MST (크루스칼)

typedef pair<int, int> ci;
typedef tuple<double, int, int> tp;

vector<int> parent;

//Find 연산
int findParent(int node) {
if (parent[node] < 0) //값이 음수면 루트 정점
return node;
return parent[node] = findParent(parent[node]); //그래프 압축하며 루트 정점 찾기
}

//Union 연산
bool unionInput(int x, int y) {
int xp = findParent(x);
int yp = findParent(y);

if (xp == yp) //같은 집합에 있다면 유니온 할 수 없음
return false;
if (parent[xp] < parent[yp]) { //새로운 루트 xp
parent[xp] += parent[yp];
parent[yp] = xp;
}
else { //새로운 루트 yp
parent[yp] += parent[xp];
parent[xp] = yp;
}
return true;
}

//kruskal
double kruskal(int v, int cnt, priority_queue<tp, vector<tp>, greater<>> &pq) {

double sum = 0;

while (cnt < v - 1) { //사용한 간선의 수가 v-1보다 적을 동안
double weight = get<0>(pq.top());
int x = get<1>(pq.top());
int y = get<2>(pq.top());
pq.pop();

if (unionInput(x, y)) {
cnt++;
sum += weight;
}
}
return sum;
}

int main() {
int n, m, a, b, cnt = 0;
priority_queue<tp, vector<tp>, greater<>> pq;

//입력
cin >> n >> m;
parent.assign(n, -1);
vector<ci> god(n);
for (int i = 0; i < n; i++){
cin >> god[i].first >> god[i].second;
}

//이미 연결된 통로 유니온 처리
for (int i = 0; i < m; i++) {
cin >> a >> b;
if (unionInput(a - 1, b - 1))
cnt++;
}

//연산
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
double xd = god[i].first - god[j].first;
double yd = god[i].second - god[j].second;
pq.push({ sqrt(xd * xd + yd * yd), i, j });
}
}

//연산 & 출력
cout << fixed;
cout.precision(2);
cout << kruskal(n, cnt, pq);
}