题解 P1550 【[USACO08OCT]打井Watering Hole】

解题报告:

这条题目乍一眼看上去真的很难很难

一点思路都没有

如果没有挖掘每一口井需要的花费,那么这条题目就变成了连接所有的点所花费的最小权值,那么问题是他每一口井还有花费,而且也不一定只挖一口井,同时井还是必须要挖的。

那么我们就要思考?

求连接一个图里面的所有节点的最小权值肯定是求这个图的最小生成树,这个肯定是毋庸置疑的,那么我们挖掘每一口的井所花费的代价是不是可以看作为该口井连有一条指向水源的边呢?

水源头我们抽象为0号节点,增加n条指向水源的边,边权值为挖井所花费的代价,那么在进行Kruskal时,要保证节点全部覆盖,那么必定有指向水源的边,即有水井被挖了。

代码如下:

#include<bits/stdc++.h>
using namespace std;
struct p{
	int x,y,z;
}a[1000005];
int tmp,tot,n,px,py,ans,f[305];
int find(int x){
	if (x==f[x]) return x;
	return f[x]=find(f[x]);
}
bool cmp(p a,p b){
	return a.z<b.z;
}
int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;i++) f[i]=i;
	for (int i=1;i<=n;i++){
		scanf("%d",&tmp);
		tot++;
		a[tot].x=0;
		a[tot].y=i;
		a[tot].z=tmp;
	}
	for (int i=1;i<=n;i++)	
		for (int j=1;j<=n;j++){
			scanf("%d",&tmp);
			if (i==j) continue;
			tot++;
			a[tot].x=i;
			a[tot].y=j;
			a[tot].z=tmp;
		}
	sort(a+1,a+tot+1,cmp);
	for (int i=1;i<=tot;i++){
		px=find(a[i].x);
		py=find(a[i].y);
		if (px==py) continue;
		f[px]=py;
		ans+=a[i].z;
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2019-04-09 20:09  dinghao1262  阅读(221)  评论(0)    收藏  举报