模板Quoit Design
解题思路
算最近点对距离的一半即可。
参考代码
#include<bits/stdc++.h>
using namespace std;
#define LOCAL //提交的时候一定注释
#define _for(i, a, b) for(int i = (a); i < (b); ++i)
#define _rep(i, a, b) for(int i = (a); i <= (b); ++i)
#define pb push_back
#define VI vector<int>
#define INF 1e20
#define mp make_pair
#define lowbit(x) ((x) & (-x))
typedef long long LL;
typedef double db;
const db eps = 1e-8; //定义浮点数误差
const int MOD = 998244353;
const int maxn = 100010;
int readint(){
int x; scanf("%d", &x); return x;
}
//计算几何
int sgn(db x) {
//判断浮点数是否为0,为0时返回0
if (fabs(x) < eps) return 0;
return x < 0 ? -1 : 1;
}
struct point{
db x, y;
point(db X = 0, db Y = 0) {
x = X, y = Y;}
point operator + (point B) {
return point{
x + B.x, y + B.y};}
point operator - (point B) {
return point{
x - B.x, y - B.y};}
point operator / (db k) {
return point{
x / k, y / k};}
point operator * (db k) {
return point{
x * k, y * k};}
bool operator == (point B) {
return sgn(x - B.x) == 0 && sgn(y - B.y) == 0;}
};
db cross(point A, point B) {
return A.x * B.y - A.y * B.x;}//求×积
db distance(point A, point B) {
return hypot(A.x - B.x, A.y - B.y);}
db polygon_area(point *p, int n) {
//求多边形的面积
db area = 0;
_for(i, 0, n) {
area += cross(p[i], p[(i + 1)%n]);
}
return area/2; //是按照三角形来算,所以这里统一除2
}
point polygon_center(point *p, int n) {
point ans(0, 0);
db area = polygon_area(p, n);
if (area == 0) return ans;
_for(i, 0, n) {
ans = ans + (p[i] + p[(i + 1)%n]) * cross(p[i], p[(i + 1)%n]);
}
return ans/area/6;
}
//判断两线段相交
bool cross_segment(point a, point b, point c, point d) {
db c1 = cross(b - a, c - a), c2 = cross(b - a, d - a);
db d1 = cross(d - c, a - c), d2 = cross(d - c, b - c);
return sgn(c1 * c2) <= 0 && sgn(d1 * d2) <= 0;
}
bool cmpxy(point a, point b) {
return sgn(a.x - b.x) < 0 || (sgn(a.x - b.x) == 0 && sgn(a.y - b.y) < 0);
}
bool cmpy(point a, point b) {
return sgn(a.y - b.y) < 0; //只对y坐标排序
}
point p[maxn], tmp_p[maxn];
//寻找最近点对
db closest_pair(int left, int right) {
db dis = INF;
if (left == right) return dis;
if (left + 1 == right) return distance(p[left], p[right]);
int mid = (left + right) / 2;
db d1 = closest_pair(left, mid);
db d2 = closest_pair(mid + 1, right);
dis = min(d1, d2);
int k = 0;
_rep(i, left, right) {
if (fabs(p[mid].x - p[i].x) <= dis) //先剪一部分
tmp_p[k++] = p[i];
}
sort(tmp_p, tmp_p + k, cmpy);
_for(i, 0, k) {
_for(j, i + 1, k) {
if (tmp_p[j].y - tmp_p[i].y >= dis) break;
dis = min(dis, distance(tmp_p[j], tmp_p[i]));
}
}
return dis;
}
int main() {
#ifdef LOCAL
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
int n;
while (~scanf("%d", &n) && n) {
_for(i, 0, n) {
scanf("%lf%lf", &p[i].x, &p[i].y);
}
sort(p, p + n, cmpxy);
printf("%.2f\n", closest_pair(0, n - 1)/2);
}
return 0;
}
删除点+标记Palace
解题思路
设点的个数 n n n, 先计算出一开始的最近点对距离 d d d ,保存他们的位置。
再计算分别去掉这两个点之后的最近点对距离 d 1 , d 2 d_1,d_2 d1,d2 。
最后的结果即为 d × ( n − 2 ) + d 1 + d 2 d\times(n-2)+d_1+d_2 d×(n−2)+d1+d2。
注意事项
1.开 l o n g l o n g long\ long long long。
2.分治法求解的时候利用好 o p t opt opt 标记。
参考代码
#include<bits/stdc++.h>
using namespace std;
#define LOCAL //提交的时候一定注释
#define _for(i, a, b) for(int i = (a); i < (b); ++i)
#define _rep(i, a, b) for(int i = (a); i <= (b); ++i)
#define pb push_back
#define VI vector<int>
#define mp make_pair
#define lowbit(x) ((x) & (-x))
typedef long long LL;
typedef double db;
const db eps = 1e-8; //定义浮点数误差
const int MOD = 998244353;
const int maxn = 1e5 + 10;
const LL INF = 1e18;
int readint(){
int x; scanf("%d", &x); return x;
}
//计算几何
int sgn(db x) {
//判断浮点数是否为0,为0时返回0
if (fabs(x) < eps) return 0;
return x < 0 ? -1 : 1;
}
struct point{
LL x, y;
int id;
point(LL X = 0, LL Y = 0, int ID = 0) {
x = X, y = Y, id = ID;}
point operator + (point B) {
return point{
x + B.x, y + B.y};}
point operator - (point B) {
return point{
x - B.x, y - B.y};}
point operator / (LL k) {
return point{
x / k, y / k};}
point operator * (LL k) {
return point{
x * k, y * k};}
bool operator == (point B) {
return sgn(x - B.x) == 0 && sgn(y - B.y) == 0;}
};
LL distance(point A, point B) {
return (A.x-B.x)*(A.x-B.x) + (A.y - B.y)*(A.y - B.y);}
bool cmpxy(point a, point b) {
return sgn(a.x - b.x) < 0 || (sgn(a.x - b.x) == 0 && sgn(a.y - b.y) < 0);
}
bool cmpy(point a, point b) {
return sgn(a.y - b.y) < 0; //只对y坐标排序
}
point p[maxn], tmp_p[maxn];
int pos[3];
//寻找最近点对
LL ans = INF; //开的是全局变量
void closest_pair(int left, int right, int opt) {
//opt为-1时代表是一开始的情况,需要记录pos
LL tmp;
if (left == right) return;
if (left + 1 == right) {
if (p[left].id != opt && p[right].id != opt) {
tmp = distance(p[left], p[right]);
if (tmp < ans) {
ans = tmp;
if (opt == -1) {
pos[0] = p[left].id;
pos[1] = p[right].id;
}
}
}
return;
}
int mid = (left + right) / 2;
closest_pair(left, mid, opt);
closest_pair(mid + 1, right, opt);
int k = 0;
_rep(i, left, right) {
if (p[i].id != opt && abs(p[mid].x - p[i].x) <= ans) //先剪一部分
tmp_p[k++] = p[i];
}
sort(tmp_p, tmp_p + k, cmpy);
_for(i, 0, k) {
_for(j, i + 1, k) {
if (tmp_p[j].y - tmp_p[i].y >= ans) break;
tmp = distance(tmp_p[i], tmp_p[j]);
if (ans > tmp) {
ans = tmp;
if (opt == -1) {
pos[0] = tmp_p[i].id, pos[1] = tmp_p[j].id;}
}
}
}
}
int main() {
#ifdef LOCAL
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
int t, n;
LL x, y;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
_for(i, 0, n) {
scanf("%lld%lld", &p[i].x, &p[i].y);
p[i].id = i;
}
sort(p, p + n, cmpxy);
point tmp;
LL sum = 0;
ans = INF;
closest_pair(0, n - 1, -1);
sum += (n - 2) * ans;
ans = INF;
closest_pair(0, n - 1, pos[0]);
sum += ans;
ans = INF;
closest_pair(0, n - 1, pos[1]);
sum += ans;
printf("%lld\n", sum);
}
return 0;
}