问题描述
给定带权无向图,求出一颗方差最小的生成树。
输入格式
输入多组测试数据。第一行为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
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
Case 2: 0.00
数据规模与约定
1<=U,V<=N<=50,N-1<=M<=1000,0<=W<=50。数据不超过5组。
这题我下载出来输入的数据,有好多都是重复边。。。很难受,想不到合适的解法了,
我就直接按照不重复来做了
多次运用最小生成树(kruskal)求解
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
int father[50+5];
int n,m;
double mi=10000000;
struct node{
int x,y,len;
double v;
};
node n1[1200];
int find(int x){
if(x==father[x]) return x;
return father[x]=find(father[x]);
}
bool cmp(node n1,node n2){
return n1.len<n2.len;
}
bool cmp2(node n1,node n2){
return n1.v<n2.v;
}
void kruskal(int sum){
for(int i=1;i<=n;i++) father[i]=i;
double avg=1.0*sum/(n-1);//已知sum可以求得平均值
for(int i=0;i<m;i++)
n1[i].v=1.0*(n1[i].len-avg)*(n1[i].len-avg);//每个边权的数-avg的平方也就能求出来
sort(n1,n1+m,cmp2);//根据数-avg的平方排序
double sum2=0;
int sum3=0,cou=0;
for(int i=0;i<m;i++){//kruskal算法
int a=find(n1[i].x),b=find(n1[i].y);
if(a==b) continue;
father[a]=b;
cou++;
sum2+=n1[i].v;
sum3+=n1[i].len;//每次用到的权值都相加
if(cou==n-1) break;
}
if(sum3==sum){//要注意的是sum只是我们假设已知的,并不一定是存在的,所以要判断一下
if(sum2<mi) mi=sum2;
}
}
int main(){
int co=0;
while(cin>>n>>m){
if(n==0||m==0) break;
mi=10000000;
for(int i=0;i<m;i++){
cin>>n1[i].x>>n1[i].y>>n1[i].len;
}
sort(n1,n1+m,cmp);
int mmin=0,mmax=0;//排序之后n-1个权值能组成的最大值和最小值
for(int i=0;i<n-1;i++){
mmin+=n1[i].len;
}
for(int i=m-1;i>m-n;i--){
mmax+=n1[i].len;
}
for(int i=mmin;i<=mmax;i++){//假设我们已经知道了sum,就是i
kruskal(i);
}
printf("Case %d: %.2f\n",++co,1.0*mi/(n-1));
}
return 0;
}
欢迎大家加入 早起学习群,一起学习一起进步!(群号:
642179511
)