PTA 公路村村通(Prim思想)

现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本。

输入格式:

输入数据包括城镇数目正整数N(≤1000)和候选道路数目M(≤3N);随后的M行对应M条道路,每行给出3个正整数,分别是该条道路直接连通的两个城镇的编号以及该道路改建的预算成本。为简单起见,城镇从1到N编号。

输出格式:

输出村村通需要的最低成本。如果输入数据不足以保证畅通,则输出−1,表示需要建设更多公路。

输入样例: 

6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3

输出样例:

12

 
思想:Prim算法
需要城镇间连通矩阵city[][],元素值为成本;
还需要一个数组dist[]存储各个城镇加入已建生成树的成本。

1.首先以第一个城镇作为标杆,建立相关信息,dist数组存储各城镇到第一个城镇的成本(其实也就是第一个城镇到各个城镇的成本)
2.然后循环n-1次查找剩下的n-1个城镇
(1)找到此时dist中加入生成树的最小花费值多对应的城镇
(2)如果此次循环没有能够符合加入条件的城市,说明不可连通,直接返回-1
(3)cost加进sum中,新加入的城市dist位置标记为0
(4)再根据刚加入的城镇,找寻矩阵,更新此时各城镇加入最小生成树的成本(每次更新都是最小, 所以每次更新其实都是查找各个未加入最小生成树的城镇到达刚加入最小生成树的城镇的成本,  查看是否相比之前加入会更小,若更小就更新dist;
3.判断是否所有的城镇都已经加入最小生成树,也就是dist是否全为0
4.全部符合条件,返回sum。 

下面为代码,超详细注解:
 

#include<stdio.h>
#define MAX 999999//自定义的城镇之间的最大值
//prim 算法思想
//将city和dist建立在mian函数外面,方便各种操作,避免各种bug
int city[1005][1005];//城镇矩阵,数值为花费,从下标1开始
int dist[1005];//各个城镇到已建城镇生成树最小花费,若已加入生成树,那么对应位置数值为0

int mincost(int n)
{

    int sum = 0;//记录总花费

    //先把第一个城镇加入到dist中作为标杆,处理相关信息
    int first = 1;//以第一个城镇为开始
    for(int i = 1; i<=n; i++){
        dist[i] = city[first][i];//此时第一个城镇为生成树,先将能与第一个城镇相连的各城镇成本输入到dist中
    }

    //找寻剩下的n-1个城镇,循环n-1次
    for(int i = 1; i<n; i++) //再循环n-1次寻找剩下的n-1个城镇接入生成树
    {
        int min_cost = MAX;//给一个初始最大值
        int min_city = -1;//给一个初始标记
        //从1到n查找此时dist中最小花费的还未加入生成树的城镇
        for(int j = 1; j<=n; j++){   
            if(dist[j] != 0 && dist[j] < min_cost)//如果比min_cost小,继续更新
            {
                min_cost = dist[j];
                min_city = j;
            }
        }

        if(min_city == -1) { //表示上次循环此城市不能接入生成树,直接退出,return-1
            return -1;
        }

        sum += min_cost;//将此次最小的花费加入到sum中
        dist[min_city] = 0;//已加入的城镇dist标记为0

        //更新dist值,以刚加入的城镇为标杆,从矩阵中查看是否有到达该城镇的最小花费的、还未加入的城镇
        for(int j = 1; j<=n; j++) {//循环n次,更新此时dist最小值
            if(dist[j] != 0 && city[min_city][j] < dist[j]  )
                dist[j] = city[min_city][j];
        }

    }

    //判断是否所有城镇都已经加入生成树,即dist是否全为0
    for(int i = 1; i<=n; i++){
        if(dist[i] != 0){
            return -1;//碰到没加入的,直接返回-1
        }
    }

    return sum;//全部操作无误,返回总和。


}
int main()
{
    int n,m;//n:城镇数 m:道路数
    scanf("%d%d",&n,&m);

    //初始化关联矩阵,均从下标1开始
    for(int i = 1; i<=n; i++){
        for(int j = 1; j<=n; j++){
            if(i == j){
                city[i][j] = 0;//对角线元素赋值0
            }else{
                city[i][j] = MAX;//赋值最大值
            }
        }
    }
    //输入给出的连通道路相关信息
    for(int i = 0; i<m; i++){
        int v1,v2,cost;
        scanf("%d%d%d",&v1,&v2,&cost);
        city[v1][v2] = cost;
        city[v2][v1] = cost;
    }

    int cost = mincost(n);
    printf("%d",cost);


    return 0;
}

 

  • 5
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值