mst
入门题,根据各个点坐标建N*(N-1)/2
个边的图。
(19年5月7日)用prim
就是循环n
次,每次找一个点,对应生成树的n
个点;而并查集就是计数n-1
条边。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <utility>
#include <cmath>
using namespace std;
const int INF = 1e9;
const int MAXC = 1e2 + 5;
int T, C;
int x[MAXC];
int y[MAXC];
vector<pair<int, double>> v[MAXC];
double d[MAXC];
double ans;
bool vis[MAXC];
void init_edge()
{
for (int i = 0; i < C - 1; i++)
{
for (int j = i + 1; j < C; j++)
{
double w = sqrt(double(pow(x[i] - x[j], 2) + pow(y[i] - y[j], 2)));
if (w >= 10.0 && w <= 1000.0)
{
v[i].push_back(make_pair(j, w));
v[j].push_back(make_pair(i, w));
}
}
}
}
void prim(int s)
{
d[s] = 0; // 没搞明白prim的堆优化,先不来了,不过想用priority_queue中的greater<int>要加头文件functional
for (int i = 0; i < C; i++)
{
double mind = INF;
int u = -1;
for (int j = 0; j < C; j++)
{
if (!vis[j] && d[j] < mind)
{
mind = d[j];
u = j;
}
}
if (u == -1)
{
ans = -1;
return;
}
ans += mind;
vis[u] = true;
for (int j = 0; j < v[u].size(); j++)
{
int k = v[u][j].first;
double w = v[u][j].second;
if (!vis[k] && w < d[k])
{
d[k] = w;
}
}
}
}
int main()
{
scanf("%d", &T);
for (; T--;)
{
scanf("%d", &C);
fill(d, d + C, INF);
fill(vis, vis + C, false);
ans = 0;
for (int i = 0; i < C; i++)
{
scanf("%d%d", &x[i], &y[i]);
v[i].clear(); // 排错
}
init_edge();
prim(0);
if (ans == -1.0) printf("oh!\n");
else printf("%.1f\n", ans * 100.0);
}
return 0;
}