#Z0739. 灌水(prim)

本文探讨了如何利用最小生成树算法解决农夫John在有限农田上进行灌溉的问题,考虑了直接供水和建设水库的成本,旨在找到最低费用的连接方案。通过Prim或Kruskal算法,将农田视为节点,连接成本包括直接水源和水库建设费用。

目录

Description

Format

Input

Output

Samples

输入数据

输出数据

分析

代码


Description

Farmer John已经决定把水灌到他的n(1<=n<=300)块农田,农田被数字1到n标记。

把一块土地进行灌水有两种方法,从其他农田饮水,或者这块土地建造水库。

建造一个水库需要花费wi(1<=wi<=100000),连接两块土地需要花费Pij(1<=pij<=100000,pij=pji,pii=0).

计算Farmer John所需的最少代价。

Format

Input

*第一行:一个数n *第二行到第n+1行:第i+1行含有一个数wi *第n+2行到第2n+1行:第n+1+i行有n个被空格分开的数,第j个数代表pij。

Output

一个单独的数代表最小代价

Samples

输入数据

4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0

输出数据

9

分析

看到题干中加了横线的部分,这足以显示:这是mst(最小生成树)

于是,首先我们要知道mst怎么做,大家可以看看这个最小生成树模板题(当然是

### Prim算法及其贪心策略 #### 什么是Prim算法Prim算法是一种用于求解图的最小生成树(Minimum Spanning Tree, MST)的经典算法。它通过逐步扩展已有的部分生成树来构建完整的最小生成树,每次选择连接当前生成树与其他未加入节点之间的最短边[^2]。 #### 贪心策略的核心思想 Prim算法基于贪心策略工作,其核心在于每一步的选择都是局部最优的,即每次都选择能够使总权重增加最少的边。这种“贪心”的决策方式最终可以证明会得到全局最优的结果——一棵具有最小权值和的生成树[^1]。 #### 算法的具体步骤 以下是Prim算法的主要操作流程: 1. **初始化** 开始时选定任意一个顶点作为起始点,并将其放入集合`S`中,其余所有顶点则位于另一个集合`V-S`中。 2. **迭代寻找最小边** 在每一次循环中,查找从集合`S`中的某个顶点出发到达集合`V-S`中任一顶点的所有可能路径上的最小权值边`(u,v)`,其中`u∈S`, `v∈V-S`。一旦找到这样的边,则把对应的顶点`v`移入集合`S`之中[^3]。 3. **更新邻接关系** 当新顶点被添加至集合`S`之后,重新评估剩余候选边上是否存在更优选项;如果存在更低成本的新连通可能性,则相应调整记录状态。 4. **终止条件** 此过程持续执行直至集合`S`覆盖整个顶点集`V`为止,此时所累积下来的全部选定点间连线共同组成了目标图的一棵最小生成树。 #### C++实现示例 下面给出了一种简单的C++语言版本的Prim算法实现方案: ```cpp #include <iostream> #include <vector> #include <limits> using namespace std; const int INF = numeric_limits<int>::max(); int prim(vector<vector<int>> &graph, int n) { vector<bool> inMST(n, false); // 是否已经在MST中 vector<int> key(n, INF); // 到达该结点所需的最小开销 vector<int> parent(n, -1); // 记录父节点 key[0] = 0; // 初始化第一个顶点为起点 for (int count = 0; count < n - 1; ++count){ int u = -1; // 寻找尚未加入MST且key值最小的顶点 for(int v=0; v<n; ++v){ if(!inMST[v] &&(u==-1 || key[v]<key[u])) u=v; } inMST[u]=true; // 更新相邻顶点的关键值 for(int v=0; v<n; ++v){ if(graph[u][v]!=INF && !inMST[v]){ if(key[v]>graph[u][v]){ key[v]=graph[u][v]; parent[v]=u; } } } } int result = 0; for(auto k : key) result +=k; return result; } // 测试函数 void test(){ int V =5 ; vector<vector<int>> graph(V ,vector<int>(V, INF)); graph[0][1]=2; graph[0][3]=6; graph[1][0]=2; graph[1][2]=3; graph[1][3]=8; graph[1][4]=5; graph[2][1]=3; graph[2][4]=7; graph[3][0]=6; graph[3][1]=8; graph[3][4]=9; graph[4][1]=5; graph[4][2]=7; graph[4][3]=9; cout << "Min Cost is "<< prim(graph,V)<< endl; } ``` 此代码片段定义了一个通用型的Prim算法框架并提供了一个小型测试案例展示如何调用上述功能计算给定无向加权图内的最小生成树总体耗费情况。 #### 应用场景分析 Prim算法广泛应用于网络设计领域,比如铺设电缆线路规划、公路建设布局优化等问题上都有实际意义。当面对大规模稀疏图时,通常推荐使用堆优先队列改进版Prim算法以提高效率性能表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值