結果
| 問題 |
No.19 ステージの選択
|
| ユーザー |
|
| 提出日時 | 2016-06-21 20:52:53 |
| 言語 | Java (openjdk 23) |
| 結果 |
AC
|
| 実行時間 | 158 ms / 5,000 ms |
| コード長 | 2,827 bytes |
| コンパイル時間 | 3,433 ms |
| コンパイル使用メモリ | 80,488 KB |
| 実行使用メモリ | 41,904 KB |
| 最終ジャッジ日時 | 2024-12-23 10:05:33 |
| 合計ジャッジ時間 | 7,439 ms |
|
ジャッジサーバーID (参考情報) |
judge4 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 24 |
ソースコード
import java.util.*;
public class Main_yukicoder19 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
UnionFind uf = new UnionFind(n);
List<List<Integer>> edges = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
edges.add(new ArrayList<>());
}
int[] l = new int[n];
for (int i = 0; i < n; i++) {
l[i] = sc.nextInt();
int s = sc.nextInt() - 1;
uf.unite(i, s);
edges.get(s).add(i);
}
Map<Integer, Double> hm = new HashMap<>();
for (int i = 0; i < n; i++) {
double tmp = dfs(i, uf.count(i), l, edges);
if (hm.containsKey(uf.find(i))) {
hm.put(uf.find(i), Math.min(hm.get(uf.find(i)), tmp));
} else {
hm.put(uf.find(i), tmp);
}
}
double ret = 0;
for (double e : hm.values()) {
ret += e;
}
System.out.printf("%.1f\n", ret);
sc.close();
}
private static double dfs(int v, int count, int[] l, List<List<Integer>> edges) {
double ret = 0;
int cnt = 0;
Queue<Integer> q = new ArrayDeque<>();
q.add(v);
ret += l[v];
cnt++;
boolean[] used = new boolean[l.length];
used[v] = true;
while (!q.isEmpty()) {
int e = q.remove();
for (int nv : edges.get(e)) {
if (!used[nv]) {
ret += (double)l[nv] / 2;
cnt++;
used[nv] = true;
q.add(nv);
}
}
}
if (cnt == count) {
return ret;
} else {
return Double.MAX_VALUE;
}
}
@SuppressWarnings("unused")
private static class UnionFind {
int n;
// cnt : 異なる集合の数
int cnt;
// parent[x] : 0~n-1 の場合、要素xのroot要素
// : -1~-n の場合、自分自身がroot要素、
// -parent[x]でxを含む集合の要素数
int[] parent;
UnionFind(int n) {
this.n = n;
cnt = n;
parent = new int[n];
Arrays.fill(parent, -1);
}
// xのrootを求める
int find(int x) {
if (parent[x] < 0) {
return x;
} else {
return parent[x] = find(parent[x]);
}
}
// xとyが同じ集合に属するのか
boolean same(int x, int y) {
return find(x) == find(y);
}
// xとyの属する集合を併合する
void unite(int x, int y) {
x = find(x);
y = find(y);
if (x == y) {
return;
}
cnt--;
// 要素数が大きい集合をrootにする(Quick Find Weighted?)
if (parent[x] > parent[y]) {
parent[y] += parent[x];
parent[x] = y;
} else {
parent[x] += parent[y];
parent[y] = x;
}
return;
}
// 要素xを含む集合の要素数
int count(int x) {
return -parent[find(x)];
}
// 異なる集合の数
int count() {
return cnt;
}
}
}