|
| 1 | +# LOJ 1029 - Civil and Evil Engineer |
| 2 | + |
| 3 | +### Problem Summary |
| 4 | + |
| 5 | +You have `n` houses `[1-n]` and a power station `0`. You are also given a set of wires, where every wire is in `u v w` format, meaning `connection from u to v costs w`. You have to use exactly `n` wires from the set to connect the houses with the power station. **The connections can be direct or indirect (through some houses) but there must be a path of wires from every house to the power station.** |
| 6 | + |
| 7 | +### Observations |
| 8 | + |
| 9 | +We can see the following properties in the problem structure. |
| 10 | + |
| 11 | +- **Graph**: We can consider the houses and the power station as `nodes` in a graph, and the wires as `edges`. Since the costs of connecting two nodes are given, and the connections have no direction, so this is a `Weighted Undirected Graph`. |
| 12 | + |
| 13 | +- **Tree**: In total, we have `n+1` nodes (`n` houses and `1` power station). We have to connect them using exactly `n` wires or `edges`. We know in a tree, for `N` nodes we have `N-1` edges. So the problem is asking us to convert the graph into a tree. |
| 14 | + |
| 15 | +- **Minimum Spanning Tree**: For the `best possible connection scheme`, We have to connect all houses with the power station using minimum cost. We have to pick `edges` in a way that satisfies the cost minimization. Therefore, we have to compute the `Minimum Spanning Tree` of the graph. |
| 16 | + |
| 17 | + - `Minimum Spanning Tree` of a graph is a subtree of that graph that contains all the `nodes` and the `sum of edge weights` is minimum possible. You can use [Prim's algorithm](https://cp-algorithms.com/graph/mst_prim.html) or [Kruskal's Algorithm](https://cp-algorithms.com/graph/mst_kruskal.html) to implement the Minimum Spanning Tree. |
| 18 | + |
| 19 | +- **Maximum Spanning Tree**: We also have to calculate the maximum possible cost to connect all the `nodes`, since this is the `worst possible connection scheme`. For this, we have to pick `edges` in a way that maximizes the cost. So we also have to compute the `Maximum Spanning Tree` of the graph. |
| 20 | + - `Maximum Spanning Tree` of a graph is a subtree of that graph that contains all the `nodes` and the `sum of edge weights` is maximum possible. We can tweak the Minimum Spanning Tree algorithm (sort the edges in descending order of the weights) to implement Maximum Spanning Tree. |
| 21 | + |
| 22 | +### Solution |
| 23 | + |
| 24 | +For every case, we have to calculate minimum spanning tree `cost1` and maximum spanning tree `cost2` and then average their costs, thus `(cost1 + cost2) / 2`. If `(cost1 + cost2)` is not divisible by `2` then we have to print in `p/q` format. Where `p` is `(cost1 + cost2)` and `q` is `2`. For example, `229/2`. |
| 25 | + |
| 26 | +### Simulation |
| 27 | + |
| 28 | +Simulation of **test case 2** is given below. |
| 29 | + |
| 30 | + |
| 31 | + |
| 32 | + |
| 33 | + |
| 34 | + |
| 35 | + |
| 36 | +And the answer is `(70 + 159) / 2`. Since `229` is not divisible by `2`, we print `229/2`. |
| 37 | + |
| 38 | +### C++ |
| 39 | + |
| 40 | +--- |
| 41 | + |
| 42 | +```C++ |
| 43 | +#include<bits/stdc++.h> |
| 44 | +using namespace std; |
| 45 | + |
| 46 | +struct edge{ |
| 47 | + int u, v, w; |
| 48 | +}; |
| 49 | + |
| 50 | +bool cmp(edge A, edge B){ |
| 51 | + return A.w < B.w; |
| 52 | +} |
| 53 | + |
| 54 | +// edge list |
| 55 | +vector < edge > G; |
| 56 | + |
| 57 | +int n; // total nodes |
| 58 | +int parent[105]; |
| 59 | + |
| 60 | +// function to clear graph |
| 61 | +void _init(){ |
| 62 | + G.clear(); |
| 63 | +} |
| 64 | + |
| 65 | +// function to find parent of a disjoint set |
| 66 | +int Find(int u){ |
| 67 | + if (u==parent[u]) return u; |
| 68 | + return parent[u] = Find(parent[u]); |
| 69 | +} |
| 70 | + |
| 71 | +// Kruskal's algorithm with Disjoint-Set Union method is used |
| 72 | +// minimum spanning tree |
| 73 | +long long MinST(){ |
| 74 | + // reset parent table [0-n] |
| 75 | + for (int i = 0; i <= n; i++) |
| 76 | + parent[i] = i; |
| 77 | + |
| 78 | + long long cost = 0; |
| 79 | + // forward iteration for minimum cost first |
| 80 | + for (int i = 0; i < G.size(); i++){ |
| 81 | + int u = G[i].u; |
| 82 | + int v = G[i].v; |
| 83 | + int w = G[i].w; |
| 84 | + |
| 85 | + int p = Find(u); |
| 86 | + int q = Find(v); |
| 87 | + if (p!=q){ |
| 88 | + cost += w; |
| 89 | + parent[q] = p; |
| 90 | + } |
| 91 | + } |
| 92 | + return cost; |
| 93 | +} |
| 94 | + |
| 95 | +// maximum spanning tree |
| 96 | +long long MaxST(){ |
| 97 | + // reset parent table [0-n] |
| 98 | + for (int i = 0; i <= n; i++) |
| 99 | + parent[i] = i; |
| 100 | + |
| 101 | + long long cost = 0; |
| 102 | + // backward iteration for maximum cost first |
| 103 | + for (int i = G.size()-1; i >= 0; i--){ |
| 104 | + int u = G[i].u; |
| 105 | + int v = G[i].v; |
| 106 | + int w = G[i].w; |
| 107 | + |
| 108 | + int p = Find(u); |
| 109 | + int q = Find(v); |
| 110 | + if (p!=q){ |
| 111 | + cost += w; |
| 112 | + parent[q] = p; |
| 113 | + } |
| 114 | + } |
| 115 | + return cost; |
| 116 | +} |
| 117 | + |
| 118 | +int main() |
| 119 | +{ |
| 120 | + int T; scanf("%d", &T); |
| 121 | + for (int cs = 1; cs <= T; cs++){ |
| 122 | + _init(); // reset graph |
| 123 | + |
| 124 | + scanf("%d", &n); |
| 125 | + int u, v, w; |
| 126 | + |
| 127 | + // take input until all u, v, w are zero (0) |
| 128 | + while ( scanf("%d%d%d", &u, &v, &w) && (u!=0 || v!=0 || w!=0) ){ |
| 129 | + G.push_back({u, v, w}); |
| 130 | + } |
| 131 | + |
| 132 | + // sorting is only done once |
| 133 | + // forward and backward iterations will be done |
| 134 | + // for ascending and descending order traversal |
| 135 | + sort(G.begin(), G.end(), cmp); |
| 136 | + |
| 137 | + long long cost1 = MinST(); |
| 138 | + long long cost2 = MaxST(); |
| 139 | + |
| 140 | + long long cost = cost1 + cost2; |
| 141 | + if (cost%2 == 0) printf("Case %d: %lld\n", cs, cost/2); |
| 142 | + else printf("Case %d: %lld/2\n", cs, cost); // cost/2 format |
| 143 | + } |
| 144 | + return 0; |
| 145 | +} |
| 146 | +``` |
0 commit comments