알고리즘

BOJ: 친구비(16562) [C++]

avocado8 2024. 6. 26. 18:44

https://www.acmicpc.net/problem/16562

 

문제

 

19학번 이준석은 학생이 N명인 학교에 입학을 했다. 준석이는 입학을 맞아 모든 학생과 친구가 되고 싶어한다. 하지만 준석이는 평생 컴퓨터랑만 대화를 하며 살아왔기 때문에 사람과 말을 하는 법을 모른다. 그런 준석이에게도 희망이 있다. 바로 친구비다!

학생 i에게 Ai만큼의 돈을 주면 그 학생은 1달간 친구가 되어준다! 준석이에게는 총 k원의 돈이 있고 그 돈을 이용해서 친구를 사귀기로 했다. 막상 친구를 사귀다 보면 돈이 부족해질 것 같다는 생각을 하게 되었다. 그래서 준석이는 “친구의 친구는 친구다”를 이용하기로 했다.

준석이는 이제 모든 친구에게 돈을 주지 않아도 된다!

위와 같은 논리를 사용했을 때, 가장 적은 비용으로 모든 사람과 친구가 되는 방법을 구하라.

입력

첫 줄에 학생 수 N (1 ≤ N ≤ 10,000)과 친구관계 수 M (0 ≤ M ≤ 10,000), 가지고 있는 돈 k (1 ≤ k ≤ 10,000,000)가 주어진다.

두번째 줄에 N개의 각각의 학생이 원하는 친구비 Ai가 주어진다. (1 ≤ Ai ≤ 10,000, 1 ≤ i ≤ N)

다음 M개의 줄에는 숫자 v, w가 주어진다. 이것은 학생 v와 학생 w가 서로 친구라는 뜻이다. 자기 자신과 친구일 수도 있고, 같은 친구 관계가 여러 번 주어질 수도 있다.

출력

준석이가 모든 학생을 친구로 만들 수 있다면, 친구로 만드는데 드는 최소비용을 출력한다. 만약 친구를 다 사귈 수 없다면, “Oh no”(따옴표 제거)를 출력한다.

 

 

친구관계는 그래프로 표현되고, 연결되어 있는지 아닌지를 판단하기 위해서는 유니온파인드를 사용

단 union을 할 때 조건 수정이 필요한데 원래는 그래프의 크기가 더 큰 쪽을 새 루트로 정했지만, 이번에는 친구비가 더 작은 쪽을 새 루트로 정해야 함

각 정점의 친구비를 저장하는 배열 cost를 만들고 조건을 추가하자

void unionInput(int x, int y) {
	int xp = findParent(x);
	int yp = findParent(y);
	if (xp == yp) { //이미 같은 집합에 속해 있다면
		return;
	}
	if (cost[xp] > cost[yp]) { //xp의 cost를 더 작게 함
		swap(xp, yp);
	}
	//cost 작은 쪽으로 union - 새로운 루트 xp
	parent[yp] = xp;
}

 

친구비를 계산하는 함수

루트 학생이랑만 칭기가 되면 나머지 칭기에게는 돈 안 줘도 되니까 루트 정점일 경우에만 친구비를 더해준다

int friendCost(int n) {
	int sum = 0;
	for (int i = 1; i <= n; i++) {
		if (parent[i] < 0) { //루트정점 친구비 더해줌
			sum += cost[i];
		}
	}
	return sum;
}

 

전체 코드

#include <iostream>
#include <vector>

using namespace std;

vector<int> parent;
vector<int> cost;

int friendCost(int n) {
	int sum = 0;
	for (int i = 1; i <= n; i++) {
		if (parent[i] < 0) { //루트정점 친구비 더해줌
			sum += cost[i];
		}
	}
	return sum;
}

int findParent(int node) {
	if (parent[node] < 0) {
		return node;
	}
	return parent[node] = findParent(parent[node]);
}

void unionInput(int x, int y) {
	int xp = findParent(x);
	int yp = findParent(y);
	if (xp == yp) { //이미 같은 집합에 속해 있다면
		return;
	}
	if (cost[xp] > cost[yp]) { //xp의 cost를 더 작게 함
		swap(xp, yp);
	}
	//cost 작은 쪽으로 union - 새로운 루트 xp
	parent[yp] = xp;
}


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

	int n, m, k, v, w;
	cin >> n >> m >> k;
	parent.assign(n + 1, -1);
	cost.resize(n + 1);
	for (int i = 1; i <= n; i++) {
		cin >> cost[i];
	}
	while (m--) {
		cin >> v >> w;
		unionInput(v, w);
	}
	int ans = friendCost(n);
	if (ans <= k) cout << ans;
	else cout << "Oh no";
	return 0;
}

 

'알고리즘' 카테고리의 다른 글

BOJ: 최소 스패닝 트리(1197) [C++]  (0) 2024.06.29
BOJ: 숫자 야구(2503) [C++]  (0) 2024.06.27
BOJ: 트리 (4803) [C++]  (0) 2024.06.25
BOJ: 집합의 표현(1717) [C++]  (0) 2024.06.24
BOJ: 파티(1238) [C++]  (0) 2024.05.27