• 引水工程 Kruskal + Prim


    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 }

     

     

     

  • 相关阅读:
    上下文管理
    复习1
    描述符
    迭代器斐波那契数列
    迭代器协议
    __call__ 方法
    析构方法__del__
    __module__和class
    1.8命令执行顺序控制与管道(学习过程)
    1.7文件系统操作与磁盘管理(学习过程)
  • 原文地址:https://www.cnblogs.com/A-FM/p/5382406.html
Copyright © 2020-2023  润新知