算法提高 最小方差生成树(Kruskal)_模板
算法提高 最小方差生成树
时间限制:1.0s 内存限制:256.0MB
问题描述
给定带权无向图,求出一颗方差最小的生成树。
输入格式
输入多组测试数据。第一行为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组。
蓝桥杯的测试数据好像有问题。。。
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <queue> 5 #include <map> 6 #include <cmath> 7 #include <stack> 8 #include <cstring> 9 #include <algorithm> 10 #include <cstdlib> 11 #define FOR(i,x,n) for(long i=x;i<n;i++) 12 #define ll long long int 13 #define INF 0x3f3f3f3f 14 #define MOD 1000000007 15 #define MAX_N 60 16 #define MAX_M 1005 17 18 using namespace std; 19 20 struct node{ 21 int u,v; 22 double wPrior; 23 double wNow; 24 }; 25 node graph[MAX_M];//储存边 26 int N,M;//点,边 27 int a[60];//并查集数组 28 29 void init(){//并查集数组初始化 30 FOR(i,1,61){ 31 a[i]=i; 32 } 33 } 34 35 bool cmp(node a,node b){ 36 return a.wNow<b.wNow; 37 } 38 39 int findCaptain(int t){//寻找队长 40 if(a[t]==t){ 41 return t; 42 }else{ 43 return a[t]=findCaptain(a[t]);//路径压缩 44 } 45 } 46 47 bool judge(int t1,int t2){//判断是否在一组内 48 return findCaptain(t1)==findCaptain(t2); 49 } 50 51 void unionPoint(int t1,int t2){//合并两点 52 int tt=findCaptain(t1); 53 int ttt=findCaptain(t2); 54 a[tt]=ttt; 55 } 56 57 double kruskal(int sum){//kruskal最小生成树 58 int edgeCount=0; 59 double sum2=0; 60 double sum3=0; 61 double ave=sum*1.0/(N-1); 62 FOR(i,0,M){ 63 graph[i].wNow=(graph[i].wPrior-ave)*(graph[i].wPrior-ave); 64 } 65 sort(graph,graph+M,cmp);//按边权从小到大排序 66 FOR(i,0,M){ 67 int t1=graph[i].u; 68 int t2=graph[i].v; 69 if(!judge(t1,t2)){ 70 unionPoint(t1,t2); 71 edgeCount++; 72 sum2+=graph[i].wPrior; 73 sum3+=graph[i].wNow; 74 if(edgeCount==N-1){ 75 break; 76 } 77 } 78 } 79 if(sum==(int)sum2){ 80 return sum3; 81 }else{ 82 return INF*1.0; 83 } 84 } 85 86 int main() 87 { 88 //freopen("input1.txt", "r", stdin); 89 //freopen("data.out", "w", stdout); 90 double t[1005]; 91 int caseCount=0; 92 double minVariance=INF*1.0; 93 while(~scanf("%d %d",&N,&M)&&(N+M)){ 94 FOR(i,0,M){ 95 scanf("%d %d %lf",&graph[i].u,&graph[i].v,&graph[i].wPrior); 96 t[i]=graph[i].wPrior; 97 } 98 sort(t,t+M); 99 double minn=0,maxx=0; 100 FOR(i,0,N-1){//找出可能的最小的average*(n-1) 101 minn+=t[i]; 102 } 103 FOR(i,M-N+1,M){//找出最大的average*(n-1) 104 maxx+=t[i]; 105 } 106 minVariance=INF*1.0; 107 FOR(i,minn,maxx+1){ 108 init(); 109 double ans=kruskal(i); 110 minVariance=min(minVariance,ans); 111 } 112 printf("Case %d: %.2f\n",++caseCount,minVariance/(N-1)); 113 114 } 115 116 //fclose(stdin); 117 //fclose(stdout); 118 return 0; 119 }