某供电公司在某省各地修建了很多的变电站,这些变电站在出现故障时需要及 时的维修,因此派遣距离这些变电站最近的工人去维修将会极大的减少维修的费用。 输入:输入第一行包含一个整数 N (1 ≤ N ≤ 100000),表示变电站和工人的数量。其后 的 2N 行,每一行有两个整数 X (0 ≤ X ≤ 1000000000),Y (0 ≤ Y ≤ 1000000000),前面的 N 行 表示变电站的位置坐标,后面的 N 行表示工人的位置坐标。 输出:1 行,也就是与这些变电站距离最近的工人所对应的最小距离,精确到小数点后 3 位。
基本上是沿用找最短两点的算法,只是需要判断一下这两个点是不是不同类的。
#include<iostream>
#include<math.h>
#include<iomanip>
#define N 100
using namespace std;
typedef struct POINT
{
double x, y;//位置坐标
int flag{ 2 };//变电站还是工人
}point, * poptr;//坐标点
double mindistance{};//变电站距离最近的工人所对应的最小距离
void quicksort(point a[], int p, int r);
int Partition(point a[], int p, int r);
double Distance(point a, point b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
double closestPoint(point s[], int low, int high) {
double d1, d2, d3{mindistance}, d;
int mid, i, j, index;
point P[N]; //辅助空间
if (high - low == 1) {
if (s[low].flag != s[high].flag)//两个点的情况
return Distance(s[low], s[high]);
else return mindistance;
}
if (high - low == 2) {
//三个点的情况
if (s[low].flag != s[low + 1].flag) d1 = Distance(s[low], s[low + 1]);
else d1 = mindistance;
if (s[low+1].flag != s[high].flag) d2 = Distance(s[low + 1], s[high]);
else d2 = mindistance;
if (s[low].flag != s[high].flag) d3 = Distance(s[low], s[high]);
else d3 = mindistance;
if ((d1 < d2) && (d1 < d3)) {
return d1;
}
else if (d2 < d3) {
return d2;
}
else {
return d3;
}
}
mid = (low + high) / 2; //其他情况递归
d1 = closestPoint(s, low, mid);
d2 = closestPoint(s, mid + 1, high);
if (d1 < d2) {
d = d1;
}
else {
d = d2;
}
index = 0;
for (i = mid; (i >= low) && ((s[mid].x - s[i].x) < d); i--) //点集合p1
P[index++] = s[i];
int pmid = index;
for (i = mid + 1; (i <= high) && ((s[i].x - s[mid].x) < d); i++) //点集合p2
P[index++] = s[i];
// quicksort(P, 0, index - 1);
for (i = 0; i < pmid; i++) {
for (j = pmid; j < index; j++)
{
if ((P[j].y - P[i].y) < d&& (P[j].x- P[i].x) < d&& P[i].flag!=P[j].flag)
{
d3 = Distance(P[i], P[j]);
if (d3 < d)
d = d3;
}
}
}
return d;
}
int Partition(point a[], int p, int r) { // 划分
point temp = a[p];
int low = p, high = r;
while (low < high) //进行一趟划分
{
while (low < high && a[high].x >= temp.x) --high;
a[low] = a[high];
while (low < high && a[low].x <= temp.x) ++low;
a[high] = a[low];
}
a[low] = temp; //找到主记录的位置low
return low;
}
void quicksort(point a[], int p, int r)
{
if (p < r) {
int q{ 0 };
q = Partition(a, p, r); //对数组进行划分,返回轴值的索引
quicksort(a, p, q - 1);
quicksort(a, q + 1, r);//
}
}
int main()
{
cout << "输入变电站和工人的数量n:";
int n; cin >> n;
point station[N]{}, worker[N]{};point allobj[N]{};
for (int i = 0; i < n; i++)//计算要输出的行数
{
cin >> allobj[i].x >> allobj[i].y;
allobj[i].flag = 1;//1--->station
}
for (int i = n; i < 2*n; i++)//计算要输出的行数
{
cin >> allobj[i].x >> allobj[i].y;
allobj[i].flag = 2;//1--->station
}
//初始化最小距离
mindistance = sqrt((allobj[0].x - allobj[n].x) * (allobj[0].x - allobj[n].x) + (allobj[0].y - allobj[n].y) * (allobj[0].y - allobj[n].y));
quicksort(allobj,0,2*n-1);
mindistance = closestPoint(allobj, 0, 2 * n - 1);
cout << fixed<<setprecision(3)<<"变电站距离最近的工人所对应的最小距离:" << mindistance;
return 0;//
}
样例输入: 4 0 0 0 1 1 0 1 1 2 2 2 3 3 2 3 3 样例输出: 1.414
附: