zoukankan      html  css  js  c++  java
  • FJUToj畅通工程1487(最小生成树)

    畅通工程(2020.12.17更新)
     
    省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。
    Input
    测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M ( < 100 );随后的 N
    行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
    Output
    对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
    SampleInput
    3 3
    1 2 1
    1 3 2
    2 3 4
    1 3
    2 3 2
    0 100
    SampleOutput
    3
    ?

    kruskal(克鲁斯卡尔)算法
    解析:目前只学了kruskal算法,所以只会用这种,其实所有的畅通工程都是一样的。像学长说的那样就是贪心+并查集,
    没了就是这两种。先将每条路拿出来,然后根据每条路的权值进行排序,然后从大到小依次向外拿,并且需要进行查看
    是否已被标记,若没有则可以将这条路算入节点中,直到把每条路遍历,最后得出的答案就是对的。(今天听了学长
    讲课才懂了这个)
     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <algorithm>
     4 using namespace std;
     5 int n,m,pre[105];
     6 struct node//存放数据
     7 {
     8     int x,y,data;
     9 }s1[105];
    10 void init()//先初始化,并查集的内容
    11 {
    12     for(int i=1;i<=n;i++)
    13     {
    14         pre[i]=i;
    15     }
    16 }
    17 int fun(int x)//查找根节点,记住最好要压缩路径
    18 {
    19     int r=x;
    20     while(r!=pre[r])
    21     {
    22         r=pre[r];
    23     }
    24     int i=x,j;
    25     while(i!=j)
    26     {
    27         j=pre[i];
    28         pre[i]=r;
    29         i=j;
    30     }
    31     return r;
    32 }
    33 bool cmp(const node &t1,const node &t2)//重载
    34 {
    35     return t1.data<t2.data;
    36 }
    37 int main(void)
    38 {
    39     while(scanf("%d%d",&n,&m)&&n)
    40     {
    41         init();
    42         for(int i=1;i<=n;i++)
    43         {
    44             scanf("%d%d%d",&s1[i].x,&s1[i].y,&s1[i].data);
    45         }
    46         sort(s1+1,s1+n+1,cmp);//对数据惊进行排序
    47         int cont=m,sum=0,x,y;
    48         for(int i=1;i<=n;i++)
    49         {
    50             x=fun(s1[i].x);
    51             y=fun(s1[i].y);
    52             if(x!=y)
    53             {
    54                 sum+=s1[i].data;
    55                 cont--;
    56                 pre[y]=x;
    57             }
    58         }
    59         if(cont==1)
    60             printf("%d\n",sum);
    61         else
    62             printf("?\n");
    63     }
    64 }

    Prim(普利姆)算法

    解析:先随意选择一个顶点加到顶点集 U 里,然后其他顶点属于顶点集 V-U 里,在这两个顶点集之间选择一条最小的边,然后将 V-U 里连接的那个点加到 U 里,将这个点从 V-U里去除,这样就形成新的两个顶点集,并且更新完两个顶点集后还要更新两个顶点集之间的边(有可能刚开始V-U里某个点跟U没链接,更新完顶点集后就有边可以连接了),然后就这样以此类推选出n-1条边,这些边相加就可以形成最小生成树(如果取最大点也可以这样,只是需要加一个标记数组)。代码里的lowcost数组是存V-U每个点顶点集到U的边长度,closest数组是V-U里的顶点与顶点集U所连接边的那另一个顶点。 

    具体过程还是以图片看比较好好理解,理论的太繁琐了(数据结构书里的图搞过来的)。

    附上代码:

     1 #include <cstdio>
     2 #include <queue>
     3 #include <iostream>
     4 #include <algorithm>
     5 #include <cmath>
     6 #include <bitset>
     7 #include <map>
     8 #include <stack>
     9 #include <stdlib.h>
    10 #include <set>
    11 #include <cstring>
    12 #include <string>
    13 #include <vector>
    14 #define ll long long
    15 #define pi acos(-1)
    16 #define mod 1000000007
    17 #define INF 0x3f3f3f3f
    18 #define exp 1e-8
    19 using namespace std;
    20 int a[105][105];
    21 int Prim(int n)
    22 {
    23     int s=1,k,sum=0;
    24     int lowcost[105],minx,closest[105];
    25     for(int i=1;i<=n;i++)
    26     {
    27         lowcost[i]=a[s][i];//V-U里每个点与U的距离
    28         closest[i]=s;//V-U里每个点连接的是U里的哪个店,这个这里可以不用
    29     }
    30     lowcost[s]=0;//这个很重要,s已经在U里了,到自己的距离为0
    31 
    32     for(int i=2;i<=n;i++)//找n-1条边
    33     {
    34         minx=INF;
    35         k=-1;
    36         for(int j=1;j<=n;j++)//找最小边
    37         {
    38             if(lowcost[j]&&lowcost[j]<minx)
    39             {
    40                 minx=lowcost[j];
    41                 k=j;
    42             }
    43         }
    44         if(minx==INF)//没有边连接直接退出
    45             return -1;
    46         lowcost[k]=0;//这个点加到U里
    47         sum+=minx;//加上值
    48         for(int j=1;j<=n;j++)//更新V-U里每个点到U的边的长
    49         {
    50             if(lowcost[j]&&a[k][j]<lowcost[j])
    51             {
    52                 lowcost[j]=a[k][j];
    53                 closest[j]=k;
    54             }
    55         }
    56     }
    57     return sum;
    58 }
    59 int main(void)
    60 {
    61     int n,x,y,w,m;
    62     while(scanf("%d%d",&m,&n))
    63     {
    64         if(!m)
    65             break;
    66         memset(a,INF,sizeof(a));//初始化每条边
    67         for(int i=1;i<=m;i++)
    68         {
    69             scanf("%d%d%d",&x,&y,&w);
    70             a[x][y]=w;//有时候也要在这里加上判断是不是最短边
    71             a[y][x]=w;
    72         }
    73         int k=Prim(n);
    74         if(k!=-1)
    75             printf("%d\n",k);
    76         else
    77             printf("?\n");
    78     }
    79 }
  • 相关阅读:
    PAT 1006 Sign In and Sign Out
    PAT 1004. Counting Leaves
    JavaEE开发环境安装
    NoSql数据库探讨
    maven的配置
    VMWARE 下使用 32位 Ubuntu Linux ,不能给它分配超过3.5G 内存?
    XCODE 4.3 WITH NO GCC?
    在苹果虚拟机上跑 ROR —— Ruby on Rails On Vmware OSX 10.7.3
    推荐一首让人疯狂的好歌《Pumped Up Kicks》。好吧,顺便测下博客园可以写点无关技术的帖子吗?
    RUBY元编程学习之”编写你的第一种领域专属语言“
  • 原文地址:https://www.cnblogs.com/zhaohongjie/p/12549073.html
Copyright © 2011-2022 走看看