一.题目链接:
HDU-5253
二.题目大意:
有一个 n × m 的图,每个点都有自己的地势高度
先要修建管道,使得每个点都联通(每个点都只能与其上下左右的点建立管道)
求所需最少的管道长度.
三.分析:
读入图后,以某个点的 上方向 和 左方向 建边.
之后最小生成树 Krual 算法即可.
注意:存边时数组要开 M * M * 2 + 5!因为这个地方WA了好几次.
四.代码实现:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-6
#define pi acos(-1.0)
#define ll long long int
using namespace std;
const int M = (int)1e3;
const int inf = 0x3f3f3ff3;
struct node
{
int u;
int v;
int w;
} Edge[2 * M * M + 5];
int mp[M + 5][M + 5];
int fa[M * M + 5];
bool cmp(node a, node b)
{
return a.w < b.w;
}
void init1(int n)
{
for(int i = 1; i <= n; ++i)
fa[i] = i;
}
int init2(int n, int m)
{
int cnt = 0;
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= m; ++j)
{
if(i == 1 && j == 1)
continue;
else if(i == 1 && j != 1)
{
Edge[cnt].u = j;
Edge[cnt].v = j - 1;
Edge[cnt].w = abs(mp[1][j] - mp[1][j - 1]);
cnt++;
}
else if(j == 1 && i != 1)
{
Edge[cnt].u = (i - 1) * m + 1;
Edge[cnt].v = (i - 2) * m + 1;
Edge[cnt].w = abs(mp[i][1] - mp[i - 1][1]);
cnt++;
}
else
{
Edge[cnt].u = (i - 1) * m + j;
Edge[cnt].v = (i - 1) * m + j - 1;
Edge[cnt].w = abs(mp[i][j] - mp[i][j - 1]);
cnt++;
Edge[cnt].u = (i - 1) * m + j;
Edge[cnt].v = (i - 2) * m + j;
Edge[cnt].w = abs(mp[i][j] - mp[i - 1][j]);
cnt++;
}
}
}
return cnt;
}
int tofind(int x)
{
if(x != fa[x])
fa[x] = tofind(fa[fa[x]]);
return fa[x];
}
int Krual(int n)
{
sort(Edge, Edge + n, cmp);
int ans = 0;
for(int i = 0; i < n; ++i)
{
int fu = tofind(Edge[i].u);
int fv = tofind(Edge[i].v);
if(fu != fv)
{
fa[fu] = fv;
ans += Edge[i].w;
}
}
return ans;
}
int main()
{
int T;
scanf("%d", &T);
for(int ca = 1; ca <= T; ++ca)
{
int n, m;
scanf("%d %d", &n, &m);
init1(n * m);
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= m; ++j)
{
scanf("%d", &mp[i][j]);
}
}
int ans = Krual(init2(n, m));
printf("Case #%d:\n", ca);
printf("%d\n", ans);
}
return 0;
}