

Kruskal题解 : 以案例输入为例 有五个缺水地区 , 这个个缺水地区之间建立联系的费用已经给出 并且之间水库的费用也已经给出 , 自己水库也已看为 是另一个 点 , 这样就有了 6 个点 , 这六个点彼此之间可以建立联系 , 总共形成 5 条边 , 将这 6 个点连接起来 , 这样就符合了题意 , 也可以更好的 用Kruskal 解决 这一个问题 , 我们可以让 这五个点 建立一个 到 0 的 距离关系 , 这样就有 0 - 6 六个点了 , 下面附上 实现代码
从水库和各个点之间的通道是单向的 ,
1 #include<stdio.h>
2 #include<string.h>
3 #include<math.h>
4 #include<iostream>
5 #include<limits.h>
6 #include<algorithm>
7 #include<queue>
8 #include<vector>
9 #include<set>
10 #include<stack>
11 #include<string>
12 #include<sstream>
13 #include<map>
14 #include<cctype>
15 using namespace std;
16 int n,m,minn,father[305],sum,tem[305];
17 struct node
18 {
19 int x,y,l;
20 }a[90005];
21 bool cmp(node a,node b)
22 {
23 return a.l<b.l;
24 }
25 int find(int x) // 做了时间上的优化 ,但是 在空间复杂度上比较高
26 {
27 if(x!=father[x])
28 father[x]=find(father[x]);
29 sum++;
30 return father[x];
31 }
32 bool merge(int x,int y) // 做了时间复杂度上的优化 让并查集的 深度尽量 浅
33 {
34 int sum1,sum2;
35 sum=0;
36 x=find(x);
37 sum1=sum; // x 的深度
38 sum=0;
39 y=find(y);
40 sum2=sum; // y 的深度
41 if(x!=y)
42 {
43 if(sum1>sum2)
44 father[y]=x;
45 else
46 father[x]=y;
47 return true;
48 }
49 else
50 return false;
51 }
52 int main() // 先用 Dijkstra 做一次 // Dijkstra 是 根据边来做的
53 {
54 int t;
55 scanf("%d",&t);
56 while(t--)
57 {
58 scanf("%d",&n);
59 for(int i=0;i<=n;i++)
60 father[i]=i;
61 int q=0;
62 for(int i=0;i<=n;i++)
63 {
64 for(int j=1;j<=n;j++)
65 {
66 int e;
67 scanf("%d",&e);
68 a[q].x=j;
69 a[q].y=i;
70 a[q].l=e;
71 q++;
72 }
73 }
74 int m=n*n,sum3=0,count1=0;
75 sort(a,a+q,cmp);
76 for(int i=0;i<q;i++)
77 {
78 if(merge(a[i].x,a[i].y))
79 {
80 sum3+=a[i].l;
81 count1++;
82 }
83 if(count1==n) // 如果边数等于 所有需要连接的 点数-1的话 就跳出去
84 break;
85 }
86 printf("%d\n",sum3);
87 }
88 return 0;
89 }
Prim 题解 : Prim 是根据 点之间的关系 去 构成最小生成树的 , 做题的思路和上面 Kruskal 处理之间水库一样 下面附上实现代码 .
1 #include<stdio.h>
2 #include<string.h>
3 #include<math.h>
4 #include<iostream>
5 #include<limits.h>
6 #include<algorithm>
7 #include<queue>
8 #include<vector>
9 #include<set>
10 #include<stack>
11 #include<string>
12 #include<sstream>
13 #include<map>
14 #include<cctype>
15 using namespace std;
16 int a[305][305],visited[305],dis[305];
17 int main()
18 {
19 int t,n;
20 scanf("%d",&t);
21 while(t--)
22 {
23 scanf("%d",&n);
24 for(int i=0;i<=n;i++)
25 {
26 dis[i]=INT_MAX;
27 for(int j=0;j<=n;j++)
28 {
29 a[i][j]=INT_MAX;
30 }
31 }
32 memset(visited,0,sizeof(visited));
33 for(int i=0;i<=n;i++)
34 {
35 for(int j=1;j<=n;j++)
36 {
37 scanf("%d",&a[i][j]); //
38 if(i==0)
39 a[j][i]=a[i][j]; // OK !
40 }
41 }
42 int n1=n,minn,j,b=0,sum=0;
43 visited[0]=1; //从水库开始吧
44 while(n1--) // 一共 n+1 个点 需要 n 个边
45 {
46 minn=INT_MAX;
47 for(int i=0;i<=n;i++)
48 {
49 if(b!=i&&a[b][i]<dis[i]&&!visited[i]) // visited 控制 是否成环
50 {
51 dis[i]=a[b][i]; // 如果不是自己到自己 并且 现在该点到 以前该点比已经确定的集合的距离短的话 ,那么就刷新距离
52 }
53 }
54 for(int i=0;i<=n;i++)
55 {
56 if(minn>dis[i]&&!visited[i])
57 {
58 minn=dis[i];
59 j=i;
60 }
61 }
62 visited[j]=1;
63 b=j;
64 sum+=minn;
65 }
66 printf("%d\n",sum);
67 }
68 return 0;
69 }