继续畅通工程
思路:
1. 比”畅通工程”多了个是否已建
2. 那么开始思考了:
可能出现这种情况:当不考虑是否已建时,某颗本来不是最小生成树(A树)的其他生成树(B树)它的总费用是40,
但由于组成B树的部分路已建,这部分路就不需要费用,假如这部分已建的路原本需要的总费用是30,
那么此时B树的建路费用是40-30=10,只需10.
而A树的建路费用是30(小于B树40,这是肯定的),但它还是比B树的实际费用高,这是完全有可能的,因为A树没有考虑已经存在的路
对上述情况演示如下,
如上图,假如三条路原本都未建(黑色),明显应该选择10+20=30,这样的建法。
如上图,假如有条路已建(红色),明显应该选择10+30,这样的建法,实际只需花费10。
但如果按照常规的过程,边集已经排好序(10,20,30),必然先10入并查集,再20入并查集,结束。错误
3.解决办法:非常简单
把路分成两部分考虑(不需要真的分成两部分存):
(1)先对所有路按费用排序
(2)把已建的加进并查集,费用不计,因为不需要考虑它的费用;
(3)在此基础上,对于剩余的路(未建的)操作就和原先相同了,即进行最小生成树算法
4.代码如下
package com.test09;
import java.util.Arrays;
import java.util.Scanner;
import com.bigDecimal.test;
class Edge3 implements Comparable<Edge3>{
int a,b;
int weight; //维护每条路(边)的费用
int pass; //路是否已建
public Edge3() {
super();
}
public Edge3(int a, int b, int weight, int pass) {
super();
this.a = a;
this.b = b;
this.weight = weight;
this.pass = pass;
}
public Edge3(int weight) {
super();
this.weight = weight;
}
@Override
public int compareTo(Edge3 o) {
return weight>o.weight? 1:(weight==o.weight? 0 : -1);
}
}
public class Main076 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
int n = sc.nextInt(); //村庄数目
if (n==0) {
return;
}
int[] tree = new int[n+1]; //题上要求村庄从1计数
for (int i = 1; i < tree.length; i++) {
tree[i] = -1;
}
//存多条边
Edge3[] edges = new Edge3[n*(n-1)/2];
for (int i = 0; i < edges.length; i++) {
edges[i] = new Edge3(sc.nextInt(), sc.nextInt(), sc.nextInt(),sc.nextInt());
}
Arrays.sort(edges);
//对于已建的
for (int i = 0; i < edges.length; i++) {
if (edges[i].pass==1) {
int a = findRoot(tree, edges[i].a);
int b = findRoot(tree, edges[i].b);
if(a!=b){
tree[a] = b;
}
}
}
//对于剩余的路进行最小生成树算法
int ans = 0; //此时才开始计总费用
for (int i = 0; i < edges.length; i++) {
if (edges[i].pass==0) {
int a = findRoot(tree, edges[i].a);
int b = findRoot(tree, edges[i].b);
if(a!=b){
tree[a] = b;
ans+=edges[i].weight;
}
}
}
//本例默认总可以找到最小生成树
System.out.println(ans);
}
}
private static int findRoot(int[] tree,int x) {
if(tree[x]==-1){
return x;
}else{
int tmp = findRoot(tree, tree[x]);
tree[x] = tmp;
return tmp;
}
}
}