[School Regional Team Contest, Saratov, 2011] - J. Minimum Sum (分治,几何)

[School Regional Team Contest, Saratov, 2011] - J. Minimum Sum (分治,几何)

题面:

题意:

在二维平面上给定\(\mathit n\)个向量,对于每一个向量,你可以使用对应的操作使其坐标变为相反数,现在让你选择两个向量\(v_i,v_j\)和其对应的操作\(k_1,k_2\),使其$|v_i^{k_1} +v_j^{k_2} | $ 最小。如果有多种方案,请输出任意一个。

思路:

通过观察四种操作,即可以对向量进行对坐标轴对称,和对原点对称。

那么我们将其问题先转化为$|v_i^{k_1} -v_j^{k_2} | $ (只要变化一下\(k_2\or k_1\) 就可以转化为$|v_i^{k_1} +v_j^{k_2} | $),

通过几何知识分析可得:$|v_i^{k_1} -v_j^{k_2} | $ ,就是向量\(v_i^{k_1} ,v_j^{k_2} \)的坐标表示法时对应的二维平面点的距离。

那么我们将所有点(将向量的起点平移到原点对应的端点。)转到第一象限,

然后用分治法求二维平面点的最短距离,同时维护出最短距离点对对应的向量信息,在输出时将一个\(\mathit k\) 转一下即可。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;

int MAX = 1e9; //定义的最大距离,以在只有一个点的时返回无穷大
int a, b;  //用来记录下标,与题无关
struct Node {
    int x, y;
    int key;   //关键码,可有可无,与ab有关
    int type;
};

Node ar[100005], br[100005];

bool cmpx(Node a, Node b) {return a.x < b.x;} //x坐标升序
bool cmpy(Node a, Node b) {return a.y < b.y;} //y坐标升序
int min(int a, int b) {return a < b ? a : b;} //返回最小值
int dis(Node a, Node b) {return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);} //返回点与点之间的距离
int ans1, ans2, ans3, ans4;
int ans_dis = 1e9;
int cal(int s, int e) //s、e用来表示当前处理的数组中的下标位置
{
    int mid, i, j, tail = 0; //mid表示数组中间的位置下标 ,tail作为计数变量,是用来br数组存储标号的
    int d;   //d表示点对之间的距离
    if (s == e) { return MAX; } //如果只有一个点
    mid = (s + e) / 2;
    d = min(cal(s, mid), cal(mid + 1, e)); //递归求出左右两边的最小距离      //下面是求是否存在左边的点到右边某点的距离小于d的点,或者是否存在在右边的点到左边某点的距离小于d的点,若是存在,必定处于一个d*2d的矩形中
    for (i = mid; i >= s && (ar[mid].x - ar[i].x) * (ar[mid].x - ar[i].x) < d; i--) { //筛选左边的点,在中间位置左侧d以内的点
        br[tail++] = ar[i];
    }

    for (i = mid + 1; i < e && (ar[i].x - ar[mid].x) * (ar[i].x - ar[mid].x) < d; i++) { //同上,筛选右边的点
        br[tail++] = ar[i];
    }
    sort(br, br + tail, cmpy);// sort for y
    for (i = 0; i < tail; i++) {//枚举矩形内点对之间的距离
        for (j = i + 1; j < tail && (br[j].y - br[i].y) * (br[j].y - br[i].y) < d; j++) {
            if (d > dis(br[i], br[j])) {      //更新点的值
                d = min(d, dis(br[i], br[j]));
                if (d < ans_dis) {
                    ans_dis = d;
                    ans1 = br[i].key;
                    ans2 = br[i].type;
                    ans3 = br[j].key;
                    ans4 = br[j].type;
                }
            }
        }
    }
    return d;                     //返回最小的点对之间的距离
}

int main()
{
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        ar[i].key = i + 1;           //关键码赋值
        scanf("%d %d", &ar[i].x, &ar[i].y);
        if (ar[i].x >= 0 && ar[i].y >= 0) {
            ar[i].type = 1;
        } else  if (ar[i].x < 0 && ar[i].y >= 0) {
            ar[i].type = 2;
        } else  if (ar[i].x >= 0 && ar[i].y < 0) {
            ar[i].type = 3;
        } else  if (ar[i].x < 0 && ar[i].y < 0) {
            ar[i].type = 4;
        }
        ar[i].x = abs(ar[i].x);
        ar[i].y = abs(ar[i].y);
    }
    sort(ar, ar + n, cmpx);        //按x对ar排序
    int d = cal(0, n);
    if (ans4 == 2) {
        ans4 = 3;
    } else if (ans4 == 3) {
        ans4 = 2;
    } else if (ans4 == 1) {
        ans4 = 4;
    } else {
        ans4 = 1;
    }
    printf("%d %d %d %d\n", ans1, ans2, ans3, ans4 );
    return 0;
}

posted @ 2020-10-27 21:38  茄子Min  阅读(107)  评论(0编辑  收藏  举报