杭电 5253 连接的管道(Kruskal-最小生成树)

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5253

思路:中文题目,要求找最短的管道。其实就是把农田看成一个个点,所以有很多的管道。因此用Prim不合适了(取线太麻烦)

代码:es数组记录管道两端农田及管道长度,因为只记录每个农田的右、下两步,故es大小不超过两倍的农田数。

#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
int map[1001][1001];
struct node
{
	int u,v,h;
}es[2000020];
int par[1000010];
int m,n;
int E;
void makeSet()
{
	for(int i=0;i<1000010;i++) par[i]=i;
	memset(map,0,sizeof(map));
	memset(es,0,sizeof(es));
}
bool cmp(node a,node b)
{
	return a.h<b.h;
}
int find(int x)
{
	if(par[x]!=x) par[x]=find(par[x]);
	return par[x];
}
int kruskal()
{
	sort(es,es+E+1,cmp);
	int res=0;
	for(int i=0;i<=E;i++)
	{
		int fx=find(es[i].v);
		int fy=find(es[i].u);
		if(fx!=fy)
		{
			par[fx]=fy;
			res+=es[i].h;
		}
	}
	return res;
}
int main()
{
	int t,cnt=0;
	cin>>t;
	while(t--)
	{
		makeSet();
		cin>>m>>n;
		for(int i=1;i<=m;i++)
			for(int j=1;j<=n;j++)
				scanf("%d",&map[i][j]);
		printf("Case #%d:\n",++cnt);
		E=0;
		for(int i=1;i<=m;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(i!=m)
				{
					es[E].u=(i-1)*n+j;
					es[E].v=i*n+j;
					es[E].h=abs(map[i][j]-map[i+1][j]);
					E++;
				}
				if(j!=n)
				{
					es[E].u=(i-1)*n+j;
					es[E].v=(i-1)*n+j+1;
					es[E++].h=abs(map[i][j]-map[i][j+1]);
				}
			}
		}
		printf("%d\n",kruskal());
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jack_jxnu/article/details/81488298