nyoj 38 布线问题 Kruskal and Prim
布线问题
时间限制:1000 ms | 内存限制:65535 KB
难度:4
- 描述
- 南阳理工学院要进行用电线路改造,现在校长要求设计师设计出一种布线方式,该布线方式需要满足以下条件:
1、把所有的楼都供上电。
2、所用电线花费最少
- 输入
- 第一行是一个整数n表示有n组测试数据。(n<5)
每组测试数据的第一行是两个整数v,e.
v表示学校里楼的总个数(v<=500)
随后的e行里,每行有三个整数a,b,c表示a与b之间如果建铺设线路花费为c(c<=100)。(哪两栋楼间如果没有指明花费,则表示这两栋楼直接连通需要费用太大或者不可能连通)
随后的1行里,有v个整数,其中第i个数表示从第i号楼接线到外界供电设施所需要的费用。( 0<e<v*(v-1)/2 )
(楼的编号从1开始),由于安全问题,只能选择一个楼连接到外界供电设备。
数据保证至少存在一种方案满足要求。 - 输出
- 每组测试数据输出一个正整数,表示铺设满足校长要求的线路的最小花费。
- 样例输入
-
1 4 6 1 2 10 2 3 10 3 1 10 1 4 1 2 4 1 3 4 1 1 3 5 6
- 样例输出
-
4
讲解:两种算法对于解决这列题目,都非常的方便的,克鲁斯卡尔,有一种贪心的感觉,线按照权值进行排序,然后选择边,而 prim 算法也是寻找最小的边,但是看起来比较麻烦,比较省时间:
AC代码一:克鲁斯卡尔算法1 2 #include<iostream> 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<string> 7 #include<cmath> 8 #include<map> 9 #include<queue> 10 using namespace std; 11 struct T 12 { 13 int x,y,z; 14 }num[125010]; 15 int cmp(T a, T b) 16 { 17 if(a.z < b.z) 18 return 1; 19 return 0; 20 } 21 int main() 22 { 23 int i,j,k,t,m,n,g,a[505],aa; 24 cin>>t; 25 while(t--) 26 { 27 cin>>m>>n; 28 int ans=0,sum=0,maxx=10000000; 29 for(i=1; i<=m; i++)//初始化的时间要注意 30 a[i]=i; 31 for( i=0; i< n; i++) 32 cin>>num[i].x>>num[i].y>>num[i].z; 33 for(i=1;i<=m;i++) 34 { 35 cin>>aa; if(aa<maxx) maxx=aa; 36 } 37 sort(num,num+n,cmp);//按照权值进行排序 38 for(i=0;i< n && sum<m-1 ; i++) 39 { 40 for(k=num[i].x ; a[k]!=k ;k=a[k]) 41 a[k]=a[a[k]]; 42 for(g=num[i].y ; a[g]!=g ;g=a[g]) 43 a[g]=a[a[g]]; 44 if(k!=g) 45 { 46 a[g]=k; 47 ans=ans+num[i].z; 48 sum++; 49 } 50 } 51 cout<<ans+maxx<<endl; 52 } 53 return 0; 54 } 55
AC代码二:普利姆算法
1 #include<stdio.h> 2 #include<string.h> 3 #define MAX 1<<28 4 int map[505][505]; 5 int e,v; 6 int prime() 7 { 8 bool flag[505];//标记数组; 9 int path[505],i,j,sum=0;//path 路径 10 for(i=1; i<=v; i++) 11 { 12 flag[i]=0;// 全部标记为0; 13 path[i]=map[1][i];//把上面的一组数 14 } 15 flag[1]=1; 16 for(i=1; i<v; i++)// v 表示的是村庄数,寻找n-1条边 17 { 18 int k , min=MAX; 19 for(j=1; j<=v; j++) 20 { 21 if( !flag[j] && path[j]<min ) //如果这个节点没有标记,并且路径小于以前的 22 { 23 min=path[j];k=j; 24 //printf("%d ",path[j]); printf("%d \n",k); 25 } 26 } 27 sum+=path[k]; 28 //printf("***\n"); 29 flag[k]=1; 30 for(j=1; j<=v; j++) 31 { 32 if( !flag[j] && path[j] > map[k][j] )//如果大于已经存在的边了,就不要它了 33 path[j]=map[k][j]; //否则继续寻找下一个节点 34 } 35 } 36 return sum; 37 } 38 int main() 39 { 40 int n; 41 scanf("%d",&n); 42 while(n--) 43 { 44 int a,b,c,i; 45 scanf("%d%d",&v,&e); 46 memset(map,9999,sizeof(map)); 47 while(e--) 48 { 49 scanf("%d%d%d",&a,&b,&c); 50 if(map[a][b]) 51 map[a][b]=map[b][a]=c<map[a][b]?c:map[a][b];//如果后来再一次出现相同的路径,则保存最小的权值 52 } 53 int min=9999999,k; 54 for(i=0;i<v;i++) 55 { 56 scanf("%d",&k); 57 if(min>k) 58 min=k; 59 } 60 printf("%d\n",prime()+min); 61 } 62 return 0; 63 }