POJ 2349 Arctic Network
1 算法
- prim求最小生成树;
- 将生成树最长的边用2卫星频道连接(如果s不允许,则最小D为该边长);
- 从剩余边中找出最长的(x,y),其将最小生成树断开为2个集合,其中一个集合set1中有拥有卫星频道的点,另一个集合set2则没有这样的点,x和y分别处于一个集合中,为处于set2的点配置1个卫星频道;
- 若s!=0,重复3操作,否则,剩余边中最长边长为最小D
2 易错点和优化
易错点: 每次为剩余边中最长边的两端点都配置卫星频道(如果未配置), 如下图(括号内为边长),当01、03已配置卫星频道, 则剩余边中最长边为02----(8)----04,要避免D>8,则需在04配置卫星频道,无需在02也配置。
01 /-----(2)-----/\-----(9)-----\ 02 03 /-(8)-/\-(1)-\ \-(6)-\ 04 05 07
优化: 刚开始时,最长边两端点配置卫星频道后(剩余s-2个卫星频道), 接下来每配置一个卫星频道,则减少一条极长边,当s-2个卫星频道用完后, 则剩余边中最长边为最开始的第(1+s-2+1 = s)长, 故D的最小值直接输出第s长的边长,不需模拟。
3 代码
3.1 AC的代码
#include <algorithm>
#include <iomanip>
#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int s, p;
int n;
double lg[500][500];
double x[500], y[500];
double dis[500];
//bool inset[500];
int father[500];
struct way
{
int x, y;
double len;
};
struct way q[500];
double len(int i, int j)
{
return sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
}
void read_data()
{
cin >> s >> p;
for (int i = 0; i < p; ++i)
{
cin >> x[i] >> y[i];
for (int j = 0; j < i; ++j)
{
lg[i][j] = len(i, j);
lg[j][i] = lg[i][j];
}
}
}
bool cmp(const struct way &a, const struct way &b)
{
return a.len > b.len;
}
/*
int find(int i)
{
int sou, tmp;
for (sou = i; father[sou] >= 0; sou = father[sou]);
while (i != sou)
{
tmp = father[i];
father[i] = sou;
i = tmp;
}
return sou;
}
void unionset(int x, int y)
{
int s1 = find(x), s2 = find(y);
if (s1 == -1)
father[s2] = s1;
else
father[s1] = s2;
}
*/
double prim()
{
double mindis;
int x, y;
int num;
for (int i = 0; i < p; ++i)
{
father[i] = 0;
dis[i] = lg[0][i];
}
dis[0] = -1;
num = 0;
while (num != p - 1)
{
mindis = 1000000000;
for (int i = 0; i < p; ++i)
if (dis[i] >= 0 && mindis > dis[i])
{
mindis = dis[i];
x = i;
}
q[num].x = x;
q[num].y = father[x];
q[num].len = mindis;
num++;
dis[x] = -1;
for (int i = 0; i < p; ++i)
if (dis[i] >= 0 && dis[i] > lg[x][i])
{
dis[i] = lg[x][i];
father[i] = x;
}
}
sort(q, q + num, cmp);
//memset(inset, 0, sizeof(inset));
if (s == 1) return q[0].len;
s -= 2;
//inset[q[0].x] = true;
//inset[q[0].y] = true;
//father[q[0].x] = -1;
//father[q[0].y] = -1;
num = 1 + s;
return q[num].len;
/*
while (s > 0)
{
for (int i = 0; i < p; ++i)
if (!inset[i]) father[i] = i;
for (int i = num + 1; i < p - 1; ++i)
{
x = q[i].x;
y = q[i].y;
if (find(x) != find(y))
unionset(x, y);
}
x = q[num].x;
y = q[num].y;
if (find(x) == -1)
{
inset[y] = true;
father[y] = -1;
}
if (find(y) == -1)
{
inset[x] = true;
father[x] = -1;
}
s--;
num++;
}
return q[num].len;
*/
}
int main()
{
cin >> n;
while (n--)
{
read_data();
printf("%.2f\n", prim());
}
return 0;
}