问题描述
给定带权无向图,求出一颗方差最小的生成树。
输入格式
输入多组测试数据。第一行为N,M,依次是点数和边数。接下来M行,每行三个整数U,V,W,代表连接U,V的边,和权值W。保证图连通。n=m=0标志着测试文件的结束。
输出格式
对于每组数据,输出最小方差,四舍五入到0.01。输出格式按照样例。
样例输入
4 5
1 2 1
2 3 2
3 4 2
4 1 1
2 4 3
4 6
1 2 1
2 3 2
3 4 3
4 1 1
2 4 3
1 3 3
0 0
样例输出
Case 1: 0.22
Case 2: 0.00
数据规模与约定
1<=U,V<=N<=50,N-1<=M<=1000,0<=W<=50。数据不超过5组。
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;
import java.util.function.Function;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
/**
* @author 翔
*
*/
public class Main {
private static ArrayList<Double> list=new ArrayList<Double>();
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
while(true){
int nodeNum=sc.nextInt();
int edgeNum=sc.nextInt();
if(nodeNum==0&&edgeNum==0){
break;
}
list.add(new Test(sc,nodeNum,edgeNum).getMinVariance());
}
for(int i=1;i<=list.size();i++){
System.out.println("Case "+i+": "+new BigDecimal(list.get(i-1)).divide(BigDecimal.ONE,2,BigDecimal.ROUND_HALF_UP));
}
}
}
class Test{
private int nodeNum;//顶点个数
private int edgeNum;//边条数
private ArrayList<Edge> edge=new ArrayList<Edge>();//边集
private ArrayList<Edge> Enew=new ArrayList<Edge>();//最小方差生成树的边集
private int[] root;//root[i]:代表i节点所在树对应的根节点
private double minVariance=Double.MAX_VALUE;//最小方差
public Test(Scanner sc,int nn,int en){
init(sc,nn,en);
}
public double getMinVariance(){
return minVariance;
}
void init(Scanner sc,int nn,int en){
nodeNum=nn;
edgeNum=en;
root=new int[nodeNum+1];
for(int i=0;i<edgeNum;i++){
edge.add(new Edge(sc.nextInt(),sc.nextInt(),sc.nextInt()));
}
Collections.sort(edge,new EdgeWeightComparator());//按照边的weight对边排序
int minAverage=0;//可能的边权均值的最小值
int maxAverage=0;//可能的边权均值的最大值
for(int i=0;i<nodeNum-1;i++){
minAverage+=edge.get(i).weight;
maxAverage+=edge.get(edgeNum-1-i).weight;
}
for(int ave=minAverage;ave<=maxAverage;ave++){
for(int i=0;i<edgeNum;i++){
double temp=edge.get(i).weight-(ave*1.0)/(nodeNum-1);
edge.get(i).cost=temp*temp;
}
Collections.sort(edge,new EdgeCostComparator());//按照边的cost对边排序
initRoot();
Enew.clear();
kruskal(ave);
}
}
/**
Kruskal算法简述:
假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:
先构造一个只含 n 个顶点,而边集为空的子图,
若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有 n 棵树的一个森林。
之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,
也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,
而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子图中含有 n-1条边为止。
*/
void kruskal(int ave){
for(int i=0;i<edgeNum&&Enew.size()<nodeNum-1;i++){
Edge tempE=edge.get(i);
if(!isInSameTree(tempE.u,tempE.v)){
Enew.add(tempE);
root[tempE.u]=root[tempE.v];
}
}
int realAverage=0;
double result=0;
for(int i=0;i<nodeNum-1;i++){
realAverage+=Enew.get(i).weight;
result+=Enew.get(i).cost;
}
result=result/(nodeNum-1);
if(realAverage==ave&&result<minVariance){
minVariance=result;
}
}
//判断两个顶点是否在同一棵树里
private boolean isInSameTree(int from,int to){
if(findRoot(from)==findRoot(to)){
return true;
}else{
return false;
}
}
//寻找某节点的根节点
private int findRoot(int i){
if(root[i]==i){
return i;
}else{
return root[i]=findRoot(root[i]);
}
}
//在边权均值改变时要重新初始化root数组
private void initRoot(){
for(int i=1;i<=nodeNum;i++){
root[i]=i;
}
}
}
class Edge{
int u;
int v;
int weight;//边权重
int cost;//(weight-average)^2
public Edge(int u,int v,int weight){
this.u=u;
this.v=v;
this.weight=weight;
}
}
class EdgeWeightComparator implements Comparator<Edge>{
public int compare(Edge arg0, Edge arg1) {
// TODO Auto-generated method stub
return arg0.weight-arg1.weight;
}
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> arg0) {
// TODO Auto-generated method stub
return null;
}
public static <T, U> Comparator<T> comparing(
Function<? super T, ? extends U> arg0, Comparator<? super U> arg1) {
// TODO Auto-generated method stub
return null;
}
public static <T> Comparator<T> comparingDouble(
ToDoubleFunction<? super T> arg0) {
// TODO Auto-generated method stub
return null;
}
public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> arg0) {
// TODO Auto-generated method stub
return null;
}
public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> arg0) {
// TODO Auto-generated method stub
return null;
}
public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
// TODO Auto-generated method stub
return null;
}
public static <T> Comparator<T> nullsFirst(Comparator<? super T> arg0) {
// TODO Auto-generated method stub
return null;
}
public static <T> Comparator<T> nullsLast(Comparator<? super T> arg0) {
// TODO Auto-generated method stub
return null;
}
public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
// TODO Auto-generated method stub
return null;
}
public Comparator<Edge> reversed() {
// TODO Auto-generated method stub
return null;
}
public Comparator<Edge> thenComparing(Comparator<? super Edge> arg0) {
// TODO Auto-generated method stub
return null;
}
public <U extends Comparable<? super U>> Comparator<Edge> thenComparing(
Function<? super Edge, ? extends U> arg0) {
// TODO Auto-generated method stub
return null;
}
public <U> Comparator<Edge> thenComparing(
Function<? super Edge, ? extends U> arg0, Comparator<? super U> arg1) {
// TODO Auto-generated method stub
return null;
}
public Comparator<Edge> thenComparingDouble(
ToDoubleFunction<? super Edge> arg0) {
// TODO Auto-generated method stub
return null;
}
public Comparator<Edge> thenComparingInt(ToIntFunction<? super Edge> arg0) {
// TODO Auto-generated method stub
return null;
}
public Comparator<Edge> thenComparingLong(ToLongFunction<? super Edge> arg0) {
// TODO Auto-generated method stub
return null;
}
}
class EdgeCostComparator implements Comparator<Edge>{
public int compare(Edge arg0, Edge arg1) {
// TODO Auto-generated method stub
if(arg0.cost>arg1.cost){
return 1;
}else{
return -1;
}
}
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> arg0) {
// TODO Auto-generated method stub
return null;
}
public static <T, U> Comparator<T> comparing(
Function<? super T, ? extends U> arg0, Comparator<? super U> arg1) {
// TODO Auto-generated method stub
return null;
}
public static <T> Comparator<T> comparingDouble(
ToDoubleFunction<? super T> arg0) {
// TODO Auto-generated method stub
return null;
}
public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> arg0) {
// TODO Auto-generated method stub
return null;
}
public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> arg0) {
// TODO Auto-generated method stub
return null;
}
public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
// TODO Auto-generated method stub
return null;
}
public static <T> Comparator<T> nullsFirst(Comparator<? super T> arg0) {
// TODO Auto-generated method stub
return null;
}
public static <T> Comparator<T> nullsLast(Comparator<? super T> arg0) {
// TODO Auto-generated method stub
return null;
}
public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
// TODO Auto-generated method stub
return null;
}
public Comparator<Edge> reversed() {
// TODO Auto-generated method stub
return null;
}
public Comparator<Edge> thenComparing(Comparator<? super Edge> arg0) {
// TODO Auto-generated method stub
return null;
}
public <U extends Comparable<? super U>> Comparator<Edge> thenComparing(
Function<? super Edge, ? extends U> arg0) {
// TODO Auto-generated method stub
return null;
}
public <U> Comparator<Edge> thenComparing(
Function<? super Edge, ? extends U> arg0, Comparator<? super U> arg1) {
// TODO Auto-generated method stub
return null;
}
public Comparator<Edge> thenComparingDouble(
ToDoubleFunction<? super Edge> arg0) {
// TODO Auto-generated method stub
return null;
}
public Comparator<Edge> thenComparingInt(ToIntFunction<? super Edge> arg0) {
// TODO Auto-generated method stub
return null;
}
public Comparator<Edge> thenComparingLong(ToLongFunction<? super Edge> arg0) {
// TODO Auto-generated method stub
return null;
}
}