标签:
题解:用kruskal算法,把每个点和右、下两个方向的点的边存起来,权值就是差值的绝对值,然后按升序排序,用并查集找到最小生成树。
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 1005;
int m, n, g[N][N], cnt, pa[1000005];
struct Edge {
int u, v, w;
}e[4000005];
long long sum, num;
bool cmp(Edge a, Edge b) {
return a.w < b.w;
}
int get_parent(int x) {
return x == pa[x] ? x : pa[x] = get_parent(pa[x]);
}
int Union(int x, int y) {
int px = get_parent(x);
int py = get_parent(y);
if (px != py) {
pa[px] = py;
return 1;
}
return 0;
}
int main() {
int t, cas = 1;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
int temp = n * m;
for (int i = 0; i < temp; i++)
pa[i] = i;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
scanf("%d", &g[i][j]);
cnt = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++) {
if (j + 1 < m) {
e[cnt].u = i * m + j;
e[cnt].v = i * m + j + 1;
e[cnt++].w = abs(g[i][j + 1] - g[i][j]);
}
if (i + 1 < n) {
e[cnt].u = i * m + j;
e[cnt].v = (i + 1) * m + j;
e[cnt++].w = abs(g[i + 1][j] - g[i][j]);
}
/* if (j - 1 >= 0) {
e[cnt].u = i * m + j;
e[cnt].v = i * m + j - 1;
e[cnt++].w = abs(g[i][j - 1] - g[i][j]);
printf("%d %d %d\n", e[cnt - 1].u, e[cnt - 1].v, e[cnt - 1].w);
}
if (i - 1 >= 0) {
e[cnt].u = i * m + j;
e[cnt].v = (i - 1) * m + j;
e[cnt++].w = abs(g[i - 1][j] - g[i][j]);
printf("%d %d %d\n", e[cnt - 1].u, e[cnt - 1].v, e[cnt - 1].w);
}*/
}
sort(e, e + cnt, cmp);
sum = 0;
for (int i = 0; i < cnt; i++)
if (Union(e[i].u, e[i].v))
sum += e[i].w;
printf("Case #%d:\n%lld\n", cas++, sum);
}
return 0;
}
标签:
原文地址:http://blog.csdn.net/hyczms/article/details/46292553