新的开始题解

题目:

发展采矿业当然首先得有矿井,小 FF 花了上次探险获得的千分之一的财富请人在岛上挖了 口矿井,但他似乎忘记考虑的矿井供电问题……

1.为了保证电力的供应,小 FF 想到了两种办法:

2.在这一口矿井上建立一个发电站,费用为 v v v(发电站的输出功率可以供给任意多个矿井)。
将这口矿井与另外的已经有电力供应的矿井之间建立电网,费用为 p p p
小 FF 希望身为「NewBe_One」计划首席工程师的你帮他想出一个保证所有矿井电力供应的最小花费。

输入:

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

输出:

9

题解:

开始碰到这个题以为是带点权的最小生成树,结果发现根本就是一道大水题,选边就不用说了直接模板即可,主要是如何建电站,可以建一个不存在的点(如:n + 1)然后将任一点与其连线,边权就是基站费用,最后用最小生成树即可。

代码:

#include 
#include 
#include 
using namespace std;
int n, m, fa[1000005], _max = -1, k, p[100005];
void Make_Set(int s) {
	for(int i = 1;i <= s; i++) fa[i] = i;
}
int Find_Set(int x) {
	if(fa[x] == x) {
		return x;
	}
	return fa[x] = Find_Set(fa[x]);
}
struct edge{
	int u, v, d;
}a[10000005];
int cmp(edge x, edge y) {
	return x.d < y.d; 
}
void Kruskal() {
	long long sum = 0;
	sort(a + 1, a + 1 + n, cmp);
	for(int i = 1;i <= n; i++) {
		int x1 = Find_Set(a[i].u), x2 = Find_Set(a[i].v);
		if(x1 != x2) {
			fa[x2] = x1;
			sum += a[i].d; 
		}
	}
	printf("%lld", sum);
} 
int main() {
	scanf("%d", &n);
	Make_Set(n);
	for(int i = 1;i <= n; i++) {
		scanf("%d", &p[i]);
		a[++k].u = i;
		a[k].v = n + 1;
		a[k].d = p[i];
	} 
	for(int i = 1;i <= n; i++) {
		for(int j = 1;j <= n; j++) {
			a[++k].u = i;
			a[k].v = j;
			scanf("%d", &a[k].d);
		} 
	} 
	n = k;
	Kruskal();
}

你可能感兴趣的:(最小生成树,图论,算法)