Portals

Solution 1 - Kruskal's

Time Complexity: O(NlogN)\mathcal{O}(N \log{N})

1// USACO 2021 US Open Gold Problem 2
2#include <iostream>
3#include <vector>
4#include <algorithm>
5using namespace std;
6void init(int n);
7bool unite(int a, int b);
8
9struct Edge
10{
11    int from, to, cost;
12};
13const int MAX_N = 100000;
14int parent[MAX_N * 2];
15int comp_size[MAX_N * 2];
16int main()
17{
18    int n;
19    cin >> n;
20    init(n * 2);
21    int cost, p1, p2, p3, p4;
22    vector<Edge> edges;
23    for (int i = 0; i < n; i++)
24    {
25        cin >> cost >> p1 >> p2 >> p3 >> p4;
26        // an edge from p1 to p2 or from p3 to p4 has 0 cost
27        edges.push_back({p1 - 1, p2 - 1, 0});
28        edges.push_back({p3 - 1, p4 - 1, 0});
29        // to get an edge from p1 to p3, we need to pay to permute the portals
30        edges.push_back({p1 - 1, p3 - 1, cost});
31    }
32    // sort edges in increasing order of cost
33    sort(edges.begin(), edges.end(), [](Edge a, Edge b){
34        return a.cost < b.cost;
35    });
36    int ans = 0;
37    for (Edge edge : edges)
38    {
39        if (unite(edge.from, edge.to))
40        {
41            ans += edge.cost;
42        }
43    }
44    cout << ans << endl;
45    return 0;
46}
47
48void init(int n)
49{
50    for (int i = 0; i < n; i++)
51    {
52        parent[i] = i;
53        comp_size[i] = 1;
54    }
55}
56
57int find(int a)
58{
59    return a == parent[a] ? a : (parent[a] = find(parent[a]));
60}
61
62bool unite(int a, int b)
63{
64    int root_a = find(a), root_b = find(b);
65    if (root_a == root_b)
66    {
67        return false;
68    }
69    if (comp_size[root_a] > comp_size[root_b])
70    {
71        swap(root_a, root_b);
72    }
73    parent[root_a] = root_b;
74    comp_size[root_b] += comp_size[root_a];
75    return true;
76}

Solution 2 - Prim's

Time Complexity: O(NlogN)\mathcal{O}(N \log{N})

1// USACO 2021 US Open Gold Problem 2 (using Prim's)
2#include <iostream>
3#include <queue>
4#include <vector>
5using namespace std;
6
7const int MAX_N = 100000;
8struct Node
9{
10    int vertex, cost;
11    bool operator>(Node other) const
12    {
13        return cost > other.cost;
14    }
15};
16int main()
17{
18    int n;
19    cin >> n;
20    priority_queue<Node, vector<Node>, greater<Node>> pq;
21    vector<Node> adj[2 * MAX_N];
22    for (int i = 0; i < n; i++)
23    {
24        int cost, p1, p2, p3, p4;
25        cin >> cost >> p1 >> p2 >> p3 >> p4;
26        p1--; p2--; p3--; p4--;
27        // an edge connecting p1 and p2 or connecting p3 and p4 has cost 0
28        adj[p1].push_back({p2, 0});
29        adj[p2].push_back({p1, 0});
30        adj[p3].push_back({p4, 0});
31        adj[p4].push_back({p3, 0});
32        // to get an edge from p1 to p3, we need to pay to permute the portals
33        adj[p1].push_back({p3, cost});
34        adj[p3].push_back({p1, cost});
35    }
36    pq.push({0, 0});
37    bool visited[2 * MAX_N]{};
38    int ans = 0;
39    // use Prim's to find the MST
40    while (!pq.empty())
41    {
42        int curr = pq.top().vertex, cost = pq.top().cost;
43        pq.pop();
44        if (visited[curr])
45        {
46            continue;
47        }
48        visited[curr] = true;
49        ans += cost;
50        // add edges from the current, visited vertex to unvisited vertices
51        for (Node next : adj[curr])
52        {
53            if (!visited[next.vertex])
54            {
55                pq.push(next);
56            }
57        }
58    }
59    cout << ans << endl;
60    return 0;
61}