传送门: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;
}