/** * Prioritise tests by c/(1-p). * If a test has an unmet dependency, then we cannot choose it yet, but we will * want to run it as soon as its parent is chosen. So update the parent node * with the priority value that would come from running the parent immediately * followed by the child. When nodes are combined like this, maintain a list of * nodes that should immediately follow in order, after a parent is eventually * chosen. * Time complexity O(n log n) * * This submission has trailing whitespace. * * @author Finn Lidbetter */ import java.util.*; public class newline_separated_trailing { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); Node[] nodes = new Node[n]; long[] costs = new long[n]; double[] probabilities = new double[n]; for (int i=0; i priority = new TreeSet<>(); for (Node node: nodes) { priority.add(node); } //printTree(priority); ArrayList sequence = new ArrayList<>(); boolean[] vis = new boolean[n]; while (priority.size() > 0) { Node minNode = priority.first(); // Only one sibling of those with a common parent definitely points // to its correct parent after some nodes may have been combined. So // find that representative. int siblingRep = uf.find(minNode.id); int parentId = nodes[siblingRep].parent; if (parentId == -1 || vis[parentId]) { // We can run this test next. // Remove it from the Binary Search Tree. priority.remove(minNode); // Mark it as visited to unblock its children. vis[minNode.id] = true; // Add the node to the sequence. sequence.add(minNode.id); // Add any followers that were combined into this node. if (minNode.followers.head != null) { LinkedListNode curr = minNode.followers.head; while (curr!=null) { sequence.add(curr.id); curr = curr.next; } } } else { // This test is blocked. We need to run its parent first. // But as soon as we run the parent we will want to run this one. Node parent = nodes[parentId]; priority.remove(minNode); priority.remove(parent); // Working out by hand shows that sequence (1,2,3) has equal cost to // sequence (3,1,2) when c3/(1-p3) = (c1+c2p2)/(1-p1p2) parent.c += minNode.c * parent.p; parent.p *= minNode.p; parent.ec = parent.c / (1-parent.p); if (minNode.children.head != null) { // We do not want to update the parent of all children. // So take the union of the set containing the children and the // set containing the min node. uf.union(minNode.id, minNode.children.head.id); int rep = uf.find(minNode.id); nodes[rep].parent = parentId; } parent.children.join(minNode.children); parent.followers.add(new LinkedListNode(minNode.id)); parent.followers.join(minNode.followers); priority.add(parent); } //printTree(priority); } StringBuilder sb = new StringBuilder(); sb.append(sequence.get(0) + 1); for (int i=1; i tree) { for (Node n: tree) { System.out.printf("id: %d, c: %d, p: %.6f, ec: %.6f\n", n.id+1, n.c, n.p, n.ec); } System.out.println(); } } class Node implements Comparable { int id; long c; double p; double ec; int parent; MyLinkedList children; MyLinkedList followers; public Node(int idd, long cc, double pp, int parentt) { id = idd; c = cc; p = pp; ec = c/(1-p); parent = parentt; children = new MyLinkedList(); followers = new MyLinkedList(); } public int compareTo(Node n2) { int comparison = (int)Math.signum(ec - n2.ec); if (comparison == 0) { return id - n2.id; } return comparison; } } class MyLinkedList { LinkedListNode head; LinkedListNode tail; public void add(LinkedListNode n) { if (head == null) { head = n; tail = n; } else { tail.next = n; tail = n; } } public void join(MyLinkedList other) { if (head == null) { if (other.head == null) { return; } head = other.head; tail = other.tail; } else { if (other.head==null) { return; } tail.next = other.head; tail = other.tail; } } } class LinkedListNode { int id; LinkedListNode next; public LinkedListNode(int idd) { id = idd; } } class UnionFind { int[] id; public UnionFind(int n) { id = new int[n]; for (int i = 0; i < n; i++) { id[i] = i; } } public int find(int p) { int rt = p; while (rt != id[rt]) { rt = id[rt]; } while (p != rt) { int next = id[p]; id[p] = rt; p = next; } return rt; } public void union(int p, int q) { int r1 = find(p); int r2 = find(q); if (r1 == r2) return; id[r1] = r2; } }