[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;
}
本博客为本人原创,如需转载,请必须声明博客的源地址。
本人博客地址为:www.cnblogs.com/qieqiemin/
希望所写的文章对您有帮助。