西南交大算法作业4:分治法

某供电公司在某省各地修建了很多的变电站,这些变电站在出现故障时需要及 时的维修,因此派遣距离这些变电站最近的工人去维修将会极大的减少维修的费用。 输入:输入第一行包含一个整数 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

附:

参考文章

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

guts350

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值