一.题目链接:

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;
}