• 算法之最小生成树(继续畅通工程)


    个人比较爱好刷算法题,然后最近遇到一个算法题,是最小生成树的问题,是继续畅通工程,首先先看下具体要求:

    省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。

    输入描述:

        测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。

        当N为0时输入结束。

    输出描述:

        每个测试用例的输出占一行,输出全省畅通需要的最低成本。
    示例1

    输入

    3
    1 2 1 0
    1 3 2 0
    2 3 4 0
    3
    1 2 1 0
    1 3 2 0
    2 3 4 1
    3
    1 2 1 0
    1 3 2 1
    2 3 4 1
    0

    输出

    3
    1
    0
    然后分析,这个题的实际就是最小生成树的问题,可以采用prim算法和kruskal算法,然后最后计算生成树的边数的总和,则就是要的结果,但是这个题比较巧妙的是又添加了一个附加条件,则是有的路已经修了,所以这个需要在输入的时候做一点点小小的改动,那就是对于已经修好的路,我们需要将其边的权重设置为0,这样,则不需要在原算法上做任何修改,则可以实现。
    使用的prim算法(具体的prim算法的思路这里不再阐述了)
    #include <stdio.h>
    
    using namespace std;
    //定义这个图的存储方式,个人比较喜欢用矩阵的方式,也可以使用邻接表的方法
    int tree[100][100];
    //记录点遍历的信息 bool isFind[100]; int main() { int n; while(scanf("%d",&n)!=EOF && n!=0) {
         //初始化数据 for(int i = 0;i<n;i++) { for(int j = 0; j<n;j++) tree[i][j] = -1; isFind[i] = false; }
         //输入数据,做一个小操作,如果输入为1,则权重为0 for(int i =0 ; i< n*(n-1)/2;i++) { int a,b,c,d; scanf("%d %d %d %d",&a,&b,&c,&d); if(d == 1) { c = 0; } tree[a-1][b-1] = c; tree[b-1][a-1] = c; }
         //用来统计路径 int countDistance = 0; while(true) { int minDistance = 10000; int minNode = 0;
    //找寻当前未遍历的点中最短的路径 for(int i = 1 ;i<n;i++) { if(!isFind[i]&&minDistance>tree[0][i]) { minDistance = tree[0][i]; minNode = i; } }
           //更新相关数据,遍历信息和总长度信息 isFind[minNode] = true; countDistance += minDistance; int isResult = true;
           //判断是否已经遍历完所有的点,是则退出,否则继续循环 for(int i = 1 ;i<n;i++) { if(!isFind[i]) isResult = false; } if(isResult) break;
    //如果没有遍历完,更新当前树与未遍历的点的信息 for(int i = 1;i<n;i++) { if(!isFind[i]) { if(tree[minNode][i]<tree[0][i]) tree[0][i] = tree[minNode][i]; } } } printf("%d\n",countDistance); } return 0; }

    下面则是kruskal算法的实现:

    #include<stdio.h>
    #include<algorithm>
    
    using namespace std;
    #define N 101
    int Tree[N];
    
    struct Edge {
        int a, b;//边两个顶点的编号
        int cost;//该边的权值
    
        bool operator<(const Edge &A) const {//重载小于号使其可以按照边权从小到大排序
            return cost < A.cost;
        }
    } edge[6000];
    
    int findRoot(int x) {//查找代表集合的树的根节点
        if (Tree[x] == -1) {
            return x;
        } else {
            int temp = findRoot(Tree[x]);
            Tree[x] = temp;
            return temp;
        }
    }
    
    int main() {
        int n;
        while (scanf("%d", &n) != EOF && n != 0) {
            int m = n * (n - 1) / 2;
            int d;
            for (int i = 1; i <= m; i++) {
                scanf("%d %d %d %d", &edge[i].a,
                      &edge[i].b, &edge[i].cost,&d);
                if(d == 1)
                    edge[i].cost = 0;
            }
            sort(edge + 1, edge + m + 1);
            for (int i = 1; i <= N; i++) {
                Tree[i] = -1;
            }
            int count = 0;//最小生成树上边权的和,初始值为0
            for (int i = 1; i <= m; i++) {//按照边权值递增排序遍历所有的边
                int aRoot = findRoot(edge[i].a);
                int bRoot = findRoot(edge[i].b);//查找两个顶点的集合信息
                if (aRoot != bRoot) {
                    Tree[aRoot] = bRoot;//合并两个集合
                    count += edge[i].cost;//累加该边权值
                }
            }
            printf("%d\n", count);//输出
        }
    
        return 0;
    }
    

      

      



  • 相关阅读:
    Account group in ERP and its mapping relationship with CRM partner group
    错误消息Number not in interval XXX when downloading
    错误消息Form of address 0001 not designated for organization
    Algorithm类介绍(core)
    梯度下降与随机梯度下降
    反思
    绘图: matplotlib核心剖析
    ORB
    SIFT
    Harris角点
  • 原文地址:https://www.cnblogs.com/cmai/p/7501079.html
Copyright © 2020-2023  润新知