灌水
#
时间限制 : 1000 MS 空间限制 : 65536 KB
问题描述
Farmer John决定给他分别用1到N(1 <= N <= 300)分别编号的牧草浇水,他可以直接在一颗牧草旁边直接挖一口井来获得水,也可以用管子从任意有水的牧草那里来获得水。
在第i颗牧草旁边挖一口井的代价为Wi(1 <= W_i <= 100,000),用管子连接第i与第j颗牧草的代价为Pij(1 <= Pij <=100,000; Pij = Pji; Pii=0)
请求出Farmer John浇灌这些牧草花费的最小代价。
输入格式
第一行,一个整数N
第二行到第N+1行,行i+1表示Wi
第N+2行到第2N+1行,行N+1+i包含N个用空格分隔开来的整数,每行第j个数字即是Pij
输出格式
仅一行,Farmer John浇灌这些牧草的最小代价。
样例输入
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
样例输出
9
解题:
1.**<最小生成树>**
2.**虚点**
难点:在哪儿打井????
**正经的解法(放大招)**
算法框架:
1.设立一个虚拟源点,表示水源
2.虚拟源点与每颗牧草连边,边权为在对应牧草旁挖井的费用
3.跑最小生成树即可。
/*
问题:
1.分不清点与边(全部)
2.tot与 i计算重复
*/
#include <bits/stdc++.h>
using namespace std;
struct node{
int a, b, len;
};
int w[300 + 5] = { };
node edge[90000 + 5] = { };
int father[90000 + 5] = { };
int n = 0;
int tot = 0;
bool cmp(node a, node b)
{
return a.len < b.len;
}
int getfather(int x)
{
if(x != father[x]){
father[x] = getfather(father[x]);
}
return father[x];
}
void kruskal()
{
int x, y, k, cnt, tt;
cnt = 0;
k = 0;
tt= 0;
while(cnt < n){
k++;
x = getfather(edge[k].a);
y = getfather(edge[k].b);
if(x != y){
father[x] = y;
tt += edge[k].len;
cnt++;
}
}
printf("%d", tt);
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%d", &w[i]);
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
int t = 0;
scanf("%d", &t);
if(i != j){
tot++;
edge[tot].a = i;
edge[tot].b = j;
edge[tot].len = t;
}
}
}
for(int i = 1; i <= n; i++){
edge[tot + i].a = n + 1;
edge[tot + i].b = i;
edge[tot + i].len = w[i];
}
tot += n;//2
for(int i = 1; i <= n + 1; i++){
father[i] = i;
}
sort(edge + 1, edge + tot + 1, cmp);
kruskal();
return 0;
}
```