《P1550 [USACO08OCT] Watering Hole G》
题目描述
Farmer John 的农场缺水了。
他决定将水引入到他的 n 个农场。他准备通过挖若干井,并在各块田中修筑水道来连通各块田地以供水。在第 i 号田中挖一口井需要花费 Wi 元。连接 i 号田与 j 号田需要 Pi,j(Pj,i=Pi,j)元。
请求出 FJ 需要为使所有农场都与有水的农场相连或拥有水井所需要的最少钱数。
输入格式
第一行为一个整数 n。
接下来 n 行,每行一个整数 Wi。
接下来 n 行,每行 n 个整数,第 i 行的第 j 个数表示连接 i 号田和 j 号田需要的费用 Pi,j。
输出格式
输出最小开销。
输入输出样例
输入 #1复制
4 5 4 4 3 0 2 2 2 2 0 3 3 2 3 0 4 2 3 4 0
输出 #1复制
9
说明/提示
对于 100% 的数据,1≤n≤300,1≤Wi≤105,0≤Pi,j≤105。
代码实现:
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
const int MAXN = 305;
const int INF = INT_MAX;
int n;
int w[MAXN]; // 挖井成本
int p[MAXN][MAXN]; // 连接成本
int dist[MAXN]; // 距离数组,用于Prim算法
bool visited[MAXN]; // 标记节点是否已访问
int main() {
cin >> n;
// 读取挖井成本
for (int i = 1; i <= n; i++) {
cin >> w[i];
}
// 读取连接成本
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> p[i][j];
}
}
// 初始化距离数组,将挖井成本视为连接到虚拟节点0的成本
for (int i = 1; i <= n; i++) {
dist[i] = w[i];
visited[i] = false;
}
int result = 0;
// Prim算法构建最小生成树
for (int i = 1; i <= n; i++) {
// 找到未访问节点中距离最小的
int min_dist = INF;
int u = -1;
for (int j = 1; j <= n; j++) {
if (!visited[j] && dist[j] < min_dist) {
min_dist = dist[j];
u = j;
}
}
if (u == -1) break; // 所有节点都已访问
visited[u] = true;
result += min_dist;
// 更新与u相邻节点的距离
for (int v = 1; v <= n; v++) {
if (!visited[v] && p[u][v] < dist[v]) {
dist[v] = p[u][v];
}
}
}
cout << result << endl;
return 0;
}