[USACO08OCT]Watering Hole

[USACO08OCT]Watering Hole

题目大意:

Farmer John 有\(n(n\le300)\)个牧场,他希望灌溉他的所有牧场。牧场编号为\(1\sim n\),要灌溉一个牧场有两种方式,一个是直接在这个牧场建设一个小型水库,另一个是从别的牧场向这个牧场引水。在第\(i\)个牧场建立小型水库需要\(W_i\)美元,而从第\(i\)个牧场向第\(j\)个牧场引水需要\(P_{i,j}\)美元。即便牧场\(j\)没有建设小型水库,只要有别的有水的水库向它引水,那它自己也有水,而且可以向别的水库引水。请告诉 FJ 灌溉所有牧场所需的最小代价。

思路:

\(P_i\)相当于连向虚点\(0\)的边,然后直接Kruskal即可。

源代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
	register char ch;
	while(!isdigit(ch=getchar()));
	register int x=ch^'0';
	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
	return x;
}
const int N=301,M=45150;
struct Edge {
	int u,v,w;
	bool operator < (const Edge &rhs) const {
		return w<rhs.w;
	}
};
Edge e[M];
int m;
class DisjointSet {
	private:
		int anc[N];
		int find(const int &x) {
			return x==anc[x]?x:anc[x]=find(anc[x]);
		}
	public:
		void reset(const int &n) {
			for(register int i=0;i<=n;i++) anc[i]=i;
		}
		void merge(const int &x,const int &y) {
			anc[find(x)]=find(y);
		}
		bool same(const int &x,const int &y) {
			return find(x)==find(y);
		}
};
DisjointSet s;
int main() {
	const int n=getint();
	for(register int i=1;i<=n;i++) {
		e[m++]=(Edge){0,i,getint()};
	}
	for(register int i=1;i<=n;i++) {
		for(register int j=1;j<=n;j++) {
			const int w=getint();
			if(j<i) e[m++]=(Edge){i,j,w};
		}
	}
	s.reset(n);
	std::sort(&e[0],&e[m]);
	int ans=0;
	for(register int i=0;i<m;i++) {
		const int &u=e[i].u,&v=e[i].v,&w=e[i].w;
		if(s.same(u,v)) continue;
		s.merge(u,v);
		ans+=w;
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2018-09-11 20:52  skylee03  阅读(159)  评论(0编辑  收藏  举报