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 ",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 ",sum); 67 } 68 return 0; 69 }