알고리즘
BOJ 1368 : 물대기
minbear
2023. 7. 25. 23:18
#BOJ 1368 : 물대기
1368번: 물대기
첫 줄에는 논의 수 N(1 ≤ N ≤ 300)이 주어진다. 다음 N개의 줄에는 i번째 논에 우물을 팔 때 드는 비용 Wi(1 ≤ Wi ≤ 100,000)가 순서대로 들어온다. 다음 N개의 줄에 대해서는 각 줄에 N개의 수가 들어
www.acmicpc.net
#풀이
문제를 읽다가 그리디로 풀어야 겠다는 생각을 했다.
한 우물은 무조건 파져야 하므로 가장 적은 비용의 우물을 파는 논을 저장하고
가장 최소 비용으로 연결하는 논들을 찾아가며 마지막에 우물파는 비용을 더했는데 틀렸다.
그 이유는 모든 논이 다른 논과 연결하는 것보다 우물파는게 더 비용이 싸다면 모든 논이 우물을 파야 하는데 나의 코드는 그러지 못했다... ㅜㅜ
쉽게 말해서 논에서 우물을 파는 비용 W가 모두 1 이고
논과 논을 있는 비용 W가 2이면
모든 논은 우물을 파는게 가장 적은 비용이지만 내가 구현한 코드는 모든 논을 연결한 다음 한 논만 우물을 파서 가장 적은 비용이 아니다.
크루스칼 알고리즘을 사용하여 최소 신장 트리를 구현하였다.
#코드
#include<iostream>
#include<vector>
#include<tuple>
#include<algorithm>
using namespace std;
int n;
tuple<int, int, int> edge[100005];
vector<int> p(302, -1);
int find(int x) {
if (p[x] < 0) return x;
return p[x] = find(p[x]);
}
bool is_diff_graph(int a, int b) {
int u = find(a); int v = find(b);
if (u == v) return 0;
if (p[u] == p[v]) p[u]--;
if (p[u] < p[v]) p[v] = u;
else p[u] = v;
return 1;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n;
int idx = 0;
for (int i = 1; i <= n; i++) {
int w;
cin >> w;
idx++;
edge[idx] = { w, i, n + 1 };
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
int w;
cin >> w;
if (w == 0)
continue;
idx++;
edge[idx] = { w, i, j };
}
}
int ans = 0;
int cnt = 0;
sort(edge + 1, edge + 1 +idx);
for (auto nxt : edge) {
int w, i, j;
tie(w, i, j) = nxt;
if (is_diff_graph(i, j) == 0) continue;
ans += w;
cnt++;
if (cnt == n) break;
}
for (int i = 1; i <= n+1; i++)
cout << p[i] << "z\n";
cout << ans << '\n';
return 0;
}