题目如下:
3 1.0 1.0 2.0 2.0 2.0 4.0
3.41
题目大意:
给出n个点的坐标(二维x, y),可以使用直线(无向的)将任意两个点连接起来,求将所有点连接起来形成一个整体(使任何两点之间可达),线的最小距离。
一个简单的最小生成树问题,这里边的权要根据输入的点的坐标信息求出,在输入的时候存储点的数组中下标可以认为是该点的编号,通过O(n^2)的复杂度来求任意两个不同点之间的距离作为权,边的两个顶点就是这段距离两端点的编号。则接下来就是简单的最小生成树算法了,可以使用kruskal也可以使用prim。
kruskal算法实现
#include <cstdio> #include <vector> #include <algorithm> #include <cmath> using namespace std; const int N = 105; struct Edge { int x, y; double w; }; struct Point { double x; double y; }; int pre[N]; Point point[N]; Edge edges[N * N / 2]; int i_p, i_e, cnt; double res; int root(int x) { if (x != pre[x]) { pre[x] = root(pre[x]); } return pre[x]; } bool merge(int x, int y) { int fx = root(x); int fy = root(y); bool ret = false; if (fx != fy) { pre[fx] = pre[fy]; ret = true; --cnt; } return ret; } void init(int n) { cnt = n; res = 0; for (int i = 0; i <= n; ++i) { pre[i] = i; } } bool cmp(const Edge &a, const Edge &b) { return a.w < b.w; } int main() { int n; double dx, dy; while (scanf("%d", &n) != EOF) { init(n); i_e = i_p = 0; for (int i = 0; i < n; ++i) { scanf("%lf %lf", &dx, &dy); point[i_p].x = dx; point[i_p].y = dy; ++i_p; } for (int i = 0; i < n; ++i) { for (int j = i + 1; j < n; ++j) { edges[i_e].x = i; edges[i_e].y = j; double dd = (point[i].x - point[j].x) * (point[i].x - point[j].x); dd += (point[i].y - point[j].y) * (point[i].y - point[j].y); edges[i_e].w = sqrt(dd); ++i_e; } } sort(edges, edges + i_e, cmp); //the cnt == 1 indicates that the mixnum spanning tree is builded sucessfully. for (int i = 0; i < i_e && cnt != 1; ++i) { if (merge(edges[i].x, edges[i].y))res += edges[i].w; } printf("%.2lf\n", res); } return 0; }
prim
#include <cstdio> #include <cmath> #include <string> #include <climits> using namespace std; const int N = 105; struct Point { double x; double y; }; Point point[N]; double dist[N], graph[N][N]; bool visit[N]; int i_p, i_e; double res; double prim(int n) { for (int i = 0; i < n; ++i) { dist[i] = graph[1][i]; } visit[1] = true; res = 0; for (int i = 1; i < n; ++i) { int min_label; double minx = INT_MAX * 1.0; for (int j = 0; j < n; ++j) { if (visit[j])continue; if (minx > dist[j]) { minx = dist[j]; min_label = j; } } visit[min_label] = true; res += minx; for (int j = 0; j < n; ++j) { if (!visit[j]) { if (dist[j] > graph[min_label][j]) { dist[j] = graph[min_label][j]; } } } } return res; } void init(int n) { memset(visit, 0, sizeof(visit)); } int main() { int n; double dx, dy; while (scanf("%d", &n) != EOF) { i_e = i_p = 0; res = 0; memset(visit, 0, sizeof(visit)); for (int i = 0; i < n; ++i) { scanf("%lf %lf", &dx, &dy); point[i_p].x = dx; point[i_p].y = dy; ++i_p; } for (int i = 0; i < n; ++i) { for (int j = i + 1; j < n; ++j) { double dd = (point[i].x - point[j].x) * (point[i].x - point[j].x); dd += (point[i].y - point[j].y) * (point[i].y - point[j].y); graph[i][j] = graph[j][i] = sqrt(dd); } } res = prim(n); printf("%.2lf\n", res); } return 0; }