• [School Regional Team Contest, Saratov, 2011]


    [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_2or 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
    ", ans1, ans2, ans3, ans4 );
        return 0;
    }
    
    
  • 相关阅读:
    去掉返回数据存在HTML节点问题
    ios8 地图不能定位问题的解决办法
    日期选择器
    定位的系统实现简单方法
    NSMutableString 的使用例子
    UIImagePickerController--------图片选取器
    代码中判断网络类型的类别
    Gitbook Android App
    Ionic 整合 pixi.js
    ionic app调试问题
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/13887760.html
Copyright © 2020-2023  润新知