算法刷题笔记 - 连接所有点的最小费用(最小生成树)

连接所有点的最小费用

题目描述
  • 给你一个points数组,表示2D平面上的一些点,其中points[i]为第i个点。

  • 连接点[xi, yi]和点 [xj, yj]的费用为它们之间的 曼哈顿距离 : |xi - xj| + |yi - yj| ,其中 |val| 表示 val的绝对值

  • 请你返回将所有点连接的最小总费用。只有任意两点之间有且仅有一条简单路径时,才认为所有点都已连接。
    输入=>结果

解法构思

结合图论或数据结构的有关知识,显然可以想到是最小生成树问题,不妨采用Prim算法

Prim算法介绍 :
Prim算法寻找最小生成树的思路是假想有两个集合,一个为已经参与建树的点集,一个为未参与建树的点集,每次都从已建树点集中的点为建树点集中的点的所有中选择权重最小的一个,这条边就加入构建生成树,相应的,这条边的终点就从未建树点集移到另一集合中, 如此反复直到所有点都参与建树则停止, 在进行过程中, 记录生成树的有关信息, 对于此题仅需要将每次选出的最小边的权重累加, 最后得到此题结果。

  • 为了提高效率, 利用一表记录每个未建树点形成的最小权值(每个未建树点, 其到每个已建树点有边, 记录其中最小者, 每个未建树点都有这么一条记录), 每当生成树增加一个点时, 更新此表。
上手编程
// 曼哈顿距离
#define PRICE(p1, p2) ( abs( (p1)[0] - (p2)[0] ) + abs( (p1)[1] - (p2)[1] ) )

int minCostConnectPoints(vector<vector<int>>& points) {
   const int N = points.size();
   
   int res = 0;  // 结果
   vector<vector<int>> W(N, vector<int>(N, 0))  // 邻接矩阵;
   vector<int> lowCost(N, 0);  // 最小权值表
   vector<char> okSet(N, 0);  // 记录每个点是否已建树, 是为1, 否为0
   
   //  建立邻接矩阵
   for (int i = 0; i < N; ++i)
       for (int j = i + 1; j < N; ++j)
           W[i][j] = W[j][i] = PRICE(points[i], points[j]);
  
   // 从0号点开始建树
   okSet[0] = true;
   
   // 初始化 / 构建此时的最小权值表
   for (int i = 1; i < N; ++i)
       lowCost[i] = W[0][i];
   
   // 一共需要再找出N-1个点建树
   for (int cnt = 1; cnt < N; ++cnt) {
       
       // 此次选出的最小权值, 及对应的出发点的序号(此点即即将参与建树的点)
       int min_price = INT_MAX, min_targetIndex = 0;
       
       // 找连接两个集合点的最小权值的边
       for (int i = 0; i < N; ++i) {
           if (!okSet[i]) {  // 仅处理 从未建树点出发的边
               if (lowCost[i] < min_price) {
                   min_price = lowCost[i];
                   min_targetIndex = i;
               }
           }
       }
       
       // 累计最小权值
       res += min_price;
       
       // 建树点集中加入刚选出的点
       okSet[min_targetIndex] = true;
       
       // 更新lowCost表
       for (int i = 0; i < N; ++i)
           if (!okSet[i]) lowCost[i] = min(lowCost[i], W[i][min_targetIndex]);
   }
   return res;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值