- 传送门 -
https://www.luogu.org/problem/show?pid=1550
时空限制 1s / 128MB
题目背景
John的农场缺水了!!!
题目描述
Farmer John has decided to bring water to his N (1 <= N <= 300) pastures which are conveniently numbered 1..N. He may bring water to a pasture either by building a well in that pasture or connecting the pasture via a pipe to another pasture which already has water.
Digging a well in pasture i costs W_i (1 <= W_i <= 100,000).
Connecting pastures i and j with a pipe costs P_ij (1 <= P_ij <= 100,000; P_ij = P_ji; P_ii=0).
Determine the minimum amount Farmer John will have to pay to water all of his pastures.
POINTS: 400
农民John 决定将水引入到他的n(1<=n<=300)个牧场。他准备通过挖若
干井,并在各块田中修筑水道来连通各块田地以供水。在第i 号田中挖一口井需要花费W_i(1<=W_i<=100,000)元。连接i 号田与j 号田需要P_ij (1 <= P_ij <= 100,000 , P_ji=P_ij)元。
请求出农民John 需要为连通整个牧场的每一块田地所需要的钱数。
输入输出格式
输入格式:
第1 行为一个整数n。
第2 到n+1 行每行一个整数,从上到下分别为W_1 到W_n。
第n+2 到2n+1 行为一个矩阵,表示需要的经费(P_ij)。
输出格式:
只有一行,为一个整数,表示所需要的钱数。
输入输出样例
输入样例#1:
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
输出样例#1:
9
说明
John等着用水,你只有1s时间!!!
- 题意 -
见题面.
- 思路 -
一开始想错了, 蓝瘦...
建一个虚点, 从每个点向其连一条边权=点权的边, 和虚点相连的点表示直接供水.
从图中取出 n 条边即可(至少要有一条边与虚点相连).
细节见代码.
PS:
没有权限号的人一开始去找bzoj1601是生气的:)
- 代码 -
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 305;
struct edge {
int x, y, v;
}W[N*N];
int C[N], D[N][N];
int F[N];
int n, ans, tot, sz, cnt;
bool cmp(edge a, edge b) { return a.v < b.v; }
int find(int x) { return F[x] == x ? x : F[x] = find(F[x]); }
void kruskal() {
for (int i = 1; i <= sz; ++i) {
int xf = find(W[i].x), yf = find(W[i].y);
if (xf == yf) continue;
F[xf] = yf;
ans += W[i].v;
cnt ++;
if (cnt == n) break;
}
}
void add(int a, int b, int v) {
W[++sz].x = a;
W[sz].y = b;
W[sz].v = v;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d", &C[i]);
F[i] = i;
add(i, 0, C[i]);
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) {
scanf("%d", &D[i][j]);
if (j > i)
add(i, j, D[i][j]);
}
sort(W + 1, W + sz + 1, cmp);
kruskal();
printf("%d
", ans);
return 0;
}