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 }

 

posted on 2014-04-14 15:53  细雨微光  阅读(259)  评论(0编辑  收藏  举报