Problem description
Farmer John became so lazy that he didn't want to continue to maintain the roads between cows. Roads are used to connect N pastures, which are consecutively numbered 1 to N. Every ranch is home to a cow. FJ plans to remove as many roads as possible from the P roads, but also maintain connectivity between ranches. You first have to decide which roads are N-1 roads to keep. The j-th two-way road connects ranch Sj and EJ (1 < = Sj < = N; 1 < = EJ < = N; Sj! = Ej), and it takes Lj time to walk through it. No two pastures are connected by more than one road. The cows are very sad because their transportation system has been cut. You need to go to every cow's house to comfort them. Every time you get to ranch i (even if you've already been there), you have to spend Ci's time talking to cows. You spend the night at the same ranch (which is your choice) until the cows are relieved from their grief. When you get up in the morning and go back to sleep at night, you need to talk to the cows in the pasture where you sleep. So that you can complete your conversation task. Assuming Farmer John takes your advice, calculate the minimum time to comfort all cows.
Input format
Line 1 contains two integers, N and P.
Next N lines, each containing an integer Ci.
Next P lines, each containing three integers Sj, Ej, and Lj.
Output format
Output an integer, the total time required (including two conversations with cows in your farm).
sample input
5 6
10
10
20
6
30
1 2 5
2 3 5
2 4 12
3 4 17
2 5 15
3 5 6
sample output
176 (data error, should be 178)
Data scale and agreement
5 <= N <= 10000,N-1 <= P <= 100000,0 <= Lj <= 1000,1 <= Ci <= 1,000.
Question meaning: the question itself is not particularly difficult, but mainly difficult to understand. It is mainly to calculate the shortest time to comfort all the cattle. All the cattle in the pasture should be comforted once, but the question meaning points out that the cattle at the starting point should be comforted twice. According to the old fellow, a minimum spanning tree is constructed according to the meaning, which is the shortest solution to the total comfort time. However, the nodes in the tree also have weights, so they can not do the routine routines. They see many ways of making old iron on the Internet. The weights and edges of the 2* edges are connected as the new comfort of the two points as the new weights of the edges, and then the minimum spanning tree method is used. Blue Bridge Cup Official Website's brocade bag also said this method.
Idea: use the structure to save the new weights of two points and between them, then add them to the priority queue. After overloading < the weights are arranged from small to large, and then use the Kruskal algorithm to solve the total time. In this algorithm, parallel query sets are used to solve the problem. For a minimum spanning tree, there are only sets. Two points contained in the elements of the priority queue are judged in turn to determine whether they belong to a set or not, and whether they do not belong to a set needs to be merged. The advantages of merging here are not obvious for small trees to be pasted on trees, which is similar to any pasting time, but path compression still needs to be done Yes, the tree always grows high, which leads to low efficiency of searching, so path compression is needed.
In the end, I found that system("pause") cannot be used on the OJ of the Blue Bridge Cup; to pause the running box, an error will be reported and a test point will fail. So we must not add the hand!!!
Code 1: stick small trees to big trees
#include <iostream> #include<queue> #include<algorithm> #define N 10010 using namespace std; struct node { int u, v, dis; node(int u, int v, int d) :u(u), v(v), dis(d) {} friend bool operator < (const node &a, const node &b) {//Overload is less than operation negative, priority queue is used return a.dis > b.dis; } }; priority_queue<node> q; int cost[N],s[N]; int find(int x) {//Find the parent node and compress the path if (s[x] < 0)return x; else { return s[x] = find(s[x]); } } void Union(int u, int v) {//Merge two nodes int rootU = find(u), rootV = find(v); if (rootU != rootV) {//For the root node, if (s[rootU] < s[rootV]) {//Value indicates the size of the root node, hanging a small tree on a large tree s[rootU] += s[rootV]; s[rootV] = rootU; } else { s[rootV] += s[rootU]; s[rootU] = rootV; } } } int kruskal() {//Using Kruskal algorithm to calculate the minimum spanning tree, for a minimum spanning tree, the parent nodes of any two points are equal int sumDis = 0; while (!q.empty()) { node tem = q.top(); q.pop(); int root1 = find(tem.u), root2 = find(tem.v); if (root1 != root2) { sumDis += tem.dis; Union(root1,root2);//Merge the two points into a set } } return sumDis; } int main(int argc, char** argv) { fill(s, s + N, -1);//Initialize parent of all nodes int n, p, a, b, c; cin >> n >> p; for (int i = 1; i <= n; i++) {//Enter the weights of all nodes scanf("%d", &cost[i]); } for (int i = 0; i < p; i++) {//Enter all nodes and all paths scanf("%d%d%d", &a, &b, &c); q.push(node{ a,b,(2 * c + cost[a] + cost[b]) }); //Double the path + the sum of two nodes on the path as the new weight of the edge } int sumCost = kruskal(); sumCost += *min_element(cost+1,cost+n);//The Min element function mainly calculates the minimum value of a given array length cout << sumCost << endl; return 0; }
Code 2: the first point is pasted on the second point
#include <iostream> #include<queue> #include<algorithm> #define N 10010 using namespace std; struct node { int u, v, dis; node(int u, int v, int d) :u(u), v(v), dis(d) {} friend bool operator < (const node &a, const node &b) {//Overload is less than operation negative, priority queue is used return a.dis > b.dis; } }; priority_queue<node> q; int cost[N], mindis, s[N]; int find(int x) {//Find the parent node and compress the path if (s[x] < 0)return x; else { return s[x] = find(s[x]); } } int kruskal() {//Using Kruskal algorithm to calculate the minimum spanning tree, for a minimum spanning tree, the parent nodes of any two points are equal int sumDis = 0; while (!q.empty()) { node tem = q.top(); q.pop(); int root1 = find(tem.u), root2 = find(tem.v); if (root1 != root2) { sumDis += tem.dis; s[root1] = root2; } } return sumDis; } int main(int argc, char** argv) { fill(s, s + N, -1);//Initialize parent of all nodes int n, p, a, b, c; cin >> n >> p; for (int i = 1; i <= n; i++) {//Enter the weights of all nodes scanf("%d", &cost[i]); } for (int i = 0; i < p; i++) {//Enter all nodes and all paths scanf("%d%d%d", &a, &b, &c); q.push(node{ a,b,(2 * c + cost[a] + cost[b]) }); //Double the path + the sum of two nodes on the path as the new weight of the edge } int sumCost = kruskal(); sumCost += *min_element(cost+1,cost+n); cout << sumCost << endl; return 0; }