洛谷题单指南-最小生成树-P1550 [USACO08OCT] Watering Hole G
原题链接:https://www.luogu.com.cn/problem/P1550
题意解读:挖n个井,每个井i直接挖的代价是w[i],如果从一个已有井i挖一条路到j,则开通井j的代价是p[i][j],求挖所有井的最小代价。
解题思路:
井可以看做图中的节点,直接挖的代价是点权值,从已开通的井挖一条路到待开通的井代价是边权,既有点权又有边权不易处理。
可以设定一个虚拟源点0,假设0号井已开通,连n条边到所有节点,边权值都是每个节点的w,表示从0号点挖一条路到各个点的代价。
要计算挖通所有点的最小代价,就是在所有路径中求最小生成树。
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 305;
struct Edge
{
int u, v, w;
} edges[N * N];
int cnt;
int p[N];
int n, ans;
bool cmp(Edge a, Edge b)
{
return a.w < b.w;
}
int find(int x)
{
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
void kruskal()
{
sort(edges + 1, edges + cnt + 1, cmp);
for(int i = 0; i <= n; i++) p[i] = i; //0 ~ n的节点
for(int i = 1; i <= cnt; i++)
{
int a = find(edges[i].u);
int b = find(edges[i].v);
if(a != b)
{
p[a] = b;
ans += edges[i].w;
}
}
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
int w;
cin >> w;
cnt++;
edges[cnt].u = 0, edges[cnt].v = i, edges[cnt].w = w;
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
int x;
cin >> x;
if(x != 0)
{
cnt++;
edges[cnt].u = i, edges[cnt].v = j, edges[cnt].w = x;
}
}
}
kruskal();
cout << ans;
return 0;
}