这个题是个典型的最小生成树的题目,但是刚开始怎么都过不了,后来发现两种写法都有疏忽,但是prim的到目前为止不懂为什么刚开始的不对,kruskal算法,并查集的初始条件从0开始写成从1开始了,所以已知wa,还有这个题比最小生成树一个卡点就是处理两点之间的距离的时候,要保证点都在10-1000之间。其它的没有什么坑了。
代码一(prim)
#include <stdio.h> #include <string.h> #include <math.h> #define INFI 999999999.0 using namespace std; const int N = 130; typedef struct point { int x, y; }point; double Map[N][N]; point p[N]; int vis[N]; double ans; double low_cost[N]; double calc(int a, int b) { return sqrt((p[b].y - p[a].y) * (p[b].y - p[a].y) + (p[b].x - p[a].x) * (p[b].x - p[a].x)); } void calc_distance(int n) { memset(Map, 0, sizeof(Map)); double t; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { t = calc(i, j); if (t >= 10 && t <= 1000) Map[i][j] = Map[j][i] =calc(i, j); else Map[i][j] = Map[j][i] = INFI; } } } int prim(int n) { for (int i = 0; i < n; i++) low_cost[i] = Map[0][i]; vis[0] = 1; for (int i = 1; i < n; i++) { int k = 0; double min = INFI; for (int j = 1; j < n; j++) { if (!vis[j] && min > low_cost[j]) { min = low_cost[j]; k = j; } } if (k != 0) { vis[k] = 1; ans += min; } else return 0; for (int j = 1; j < n; j++) { if (!vis[j] && Map[k][j] < low_cost[j]) low_cost[j] = Map[k][j]; } } return 1; } int main() { int T, C; scanf("%d", &T); while (T--) { memset(vis, 0, sizeof(vis)); ans = 0.0; scanf("%d", &C); for (int i = 0; i < C; ++i) scanf("%d %d", &p[i].x, &p[i].y); calc_distance(C); int t = prim(C); if (t == 0) { puts("oh!"); continue; } ans *= 100.0; printf("%.1f ", ans); } return 0; }
代码二(kruskal)
#include<iostream> #include <stdio.h> #include <string.h> #include <math.h> #include <algorithm> #define EPS 1e-10 using namespace std; struct Point{ int x, y; }; struct edge{ int s, e; double dis; }; const int N = 123; int father[N], num[N]; Point p[N]; edge E[N * N / 2]; double ans = 0.0; void init(int n) { for (int i = 0; i <= n; ++i) { father[i] = i; num[i] = 1; } } double calct(int a, int b) { return sqrt((p[b].y - p[a].y) * (p[b].y - p[a].y) + (p[b].x - p[a].x) * (p[b].x - p[a].x)); } int calc_distance(int n) { int k = 0; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { double t = calct(i, j); if (t >= 10.0 && t <= 1000.0) { E[k].s = i; E[k].e = j; E[k++].dis = t; } } } return k; } bool cmp(edge a, edge b) { return a.dis < b.dis; } int find(int x) { while (x != father[x]) x = father[x]; return father[x]; } bool merge(int a, int b) { int ta = find(a); int tb = find(b); if (ta == tb) return false; if (num[ta] > num[tb]) { father[tb] = ta; num[ta] += num[tb]; } else { father[ta] = tb; num[tb] += num[ta]; } return true; } bool kruskal(int n, int len) { int k = 0; for (int i = 0; i < len; i++) { if (merge(E[i].s, E[i].e)) { ++k; ans += E[i].dis; } if (k == n - 1) break; } if (k == n - 1) return true; return false; } int main() { int t,n; scanf("%d", &t); while (t--) { scanf("%d", &n); init(n); ans = 0.0; for (int i = 0; i < n; i++) scanf("%d %d", &p[i].x, &p[i].y); int len = calc_distance(n); sort(E, E + len, cmp); if (kruskal(n, len)) { printf("%.1f ", ans * 100.0); } else puts("oh!"); } return 0; }