计算几何基本模板
//浮点误差
const double eps = 1e-8;
//点/向量
struct Vec{
double x, y;
Vec() {}
Vec(double _x, double _y) : x(_x), y(_y) {}
inline double angle() const{return atan2(y,x);}
inline double len() const{return sqrt(x*x+y*y);}
inline Vec l_rot() const{return Vec(-y,x);}
inline Vec r_rot() const{return Vec(y,-x);}
};
inline Vec operator + (const Vec &a, const Vec &b){return Vec(a.x+b.x,a.y+b.y);}
inline Vec operator - (const Vec &a, const Vec &b){return Vec(a.x-b.x,a.y-b.y);}
template<typename T> inline Vec operator * (const Vec &a, T b){return Vec(a.x*b,a.y*b);}
template<typename T> inline Vec operator * (T a, const Vec &b){return Vec(a*b.x,a*b.y);}
template<typename T> inline Vec operator / (const Vec &a, T b){return Vec(a.x/b,a.y/b);}
inline double dot (const Vec &a, const Vec &b){return a.x*b.x+a.y*b.y;}
inline double cross (const Vec &a, const Vec &b){return a.x*b.y-a.y*b.x;}
typedef Vec Poi;
//直线/线段
struct Line{
Poi op, ed; double k, b, ang;
Line(){}
Link(Poi A, Poi B):op(A),ed(B){
k = (A.y-B.y)/(A.x-B.x); b = A.y-k*A.x;
ang = atan2(k);
}
}
//圆
struct Circle{
Poi O; double r;
}
//浮点数比较大小
inline bool gt(double x, double y = 0.){ return x>y+eps; }
inline bool lt(double x, double y = 0.){ return x<y-eps; }
inline bool ge(double x, double y = 0.){ return x>=y-eps; }
inline bool le(double x, double y = 0.){ return x<=y+eps; }
inline bool eq(double x, double y = 0.){ return fabs(x-y)<=eps; }
//直线求交
inline Poi GetIntersection(const Line &a, const Line &b){
double x = cross(a.ed-a.op, b.ed-b.op);
double y = cross(b.op-a.op, a.ed-a.op);
return b.op+(b.ed-b.op)*y/x;
}
//两圆求交
inline void GetIntersection(Circle O1, Circle O2, double dis){
double alpha = atan2(O2.O.y-O1.O.y, O2.O.x-O1.O.x)+pi, // alpha /in (0, 2pi]
beta = acos((O1.r*O1.r+dis*dis-O2.r*O2.r)/(2*O1.r*dis)); //beta /in (0, pi]
pair<double, double> tmp = MP(alpha-beta, alpha+beta);
if (ge(tmp.FT) && le(tmp.SC, 2*pi)) Interval[++tot] = tmp;
else if (lt(tmp.FT)){ Interval[++tot] = MP(tmp.FT+2*pi, 2*pi); Interval[++tot] = MP(0, tmp.SC); }
else if (gt(tmp.SC, 2*pi)){ Interval[++tot] = MP(tmp.FT, 2*pi); Interval[++tot] = MP(0, tmp.SC-2*pi); }
}
//极角区间并
inline double IntervalUnion(){
double res = 0., L = -1., R = -1.;
sort(Interval+1, Interval+1+tot);
rep(i, 1, tot){
if (gt(Interval[i].FT, R)) res += R-L, L = Interval[i].FT, R = Interval[i].SC;
else if (gt(Interval[i].SC, R)) R = Interval[i].SC;
}
res += R-L;
return 2*pi-res;
}
//判断点在有向线段的左侧
inline bool OnLeft(const Line &a, const Poi &b){
return le(cross(b-a.op, a.ed-a.op));
}
//三角形外心
//设a(x1,y1),b(x2,y2),c(x3,y3),外心o(x,y)
//由定义ao=bo,bo=co,得到一个二次式
//换元 Ax=2(x2-x1),Ay=2(x3-x2),
// Bx=2(y2-y1),By=2(y3-y2),
// Cx=x2^2+y2^2-x1^2-y1^2,Cy=x3^2+y3^2-x2^2-y2^2
//得到x=(CxBy-CyBx)/(AxBy-AyBx)
// y=(CxAy-CyAx)/(BxAy-ByAx),是叉积的形式
inline Poi solve(Poi a, Poi b, Poi c){
Poi A = 2*Vec(b.x-a.x, c.x-b.x);
Poi B = 2*Vec(b.y-a.y, c.y-b.y);
Poi C = Vec(sqr(b.len())-sqr(a.len()), sqr(c.len())-sqr(b.len()));
double x = cross(C, B), y = cross(C, A), M = cross(A, B);
return Vec(x,-y)/M;
}
//求凸包面积
inline double CalS(){ double ans = 0.;
if (n < 3) return ans;
CH[n+1] = CH[1]; rep(i, 1, n) ans += cross(CH[i], CH[i+1]);
return fabs(ans)/2.;
}
//水平序凸包
//Andrew Scan
//O(nlogn)
inline void ConvexHull(){
static Poi stack[MaxN]; int top = 0;
rep(i, 1, n){
while (top >= 2 && ge0(cross(stack[top]-stack[top-1], p[i]-stack[top]))) top--;
stack[++top] = p[i];
}
rep(i, 1, top) CH[++r] = stack[i]; top = 0;
rep(i, 1, n){
while (top >= 2 && le0(cross(stack[top]-stack[top-1], p[i]-stack[top]))) top--;
stack[++top] = p[i];
}
per(i, top-1, 2) CH[++r] = stack[i]; top = 0;
}
//半平面交
//S&I算法
//O(nlogn)
inline void HalfPlainIntersection(){
int tot = 0; sort(line+1, line+1+n);
rep(i, 1, n){
if (!eq(line[i].ang, line[i-1].ang)) tot++;
line[tot] = line[i];
}
int l = 1, r = 0; q[++r] = line[1]; q[++r] = line[2];
rep(i, 3, tot){
for (; l < r && !OnLeft(line[i], GetIntersection(q[r], q[r-1])); r--);
for (; l < r && !OnLeft(line[i], GetIntersection(q[l], q[l+1])); l++);
q[++r] = line[i];
}
for (; l < r && !OnLeft(q[l], GetIntersection(q[r], q[r-1])); r--);
for (; l < r && !OnLeft(q[r], GetIntersection(q[l], q[l+1])); l++);
q[r+1] = q[l];
n = 0; rep(i, l, r) CH[++n] = GetIntersection(q[i], q[i+1]);
}
//辛普森自适应积分
inline double Simpson(double fl, double fr, double fmid, double h){ return h*(fl+4*fmid+fr)/6.0; }
inline double Integral(double l, double r, double mid, double fl, double fr, double fmid, double S){
double lmid = (l+mid)/2.0, rmid = (mid+r)/2.0;
double flmid = f(lmid), frmid = f(rmid);
double lS = Simpson(fl, fmid, flmid, mid-l), rS = Simpson(fmid, fr, frmid, r-mid);
if (eq(lS + rS, S)) return S;
return Integral(l, mid, lmid, fl, fmid, flmid, lS)+Integral(mid, r, rmid, fmid, fr, frmid, rS);
}
点集三角形覆盖计数
给一个点集,统计覆盖了原点的三角形个数
解:
枚举点
i
,原点与
(BZOJ1914)
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define MS(_) memset(_, 0, sizeof(_))
#define MP make_pair
#define PB push_back
#define debug(...) fprintf(stderr, __VA_ARGS__)
template<typename T> inline void read(T &x){
x = 0; T f = 1; char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
x *= f;
}
typedef long long ll;
const double eps = 1e-7;
const int N = 111111;
struct Vec{
double x, y, angle;
Vec() {}
Vec(double _x, double _y) : x(_x), y(_y) {angle = atan2(y, x);}
inline void cal_angle() {angle = atan2(y, x);}
};
inline Vec operator + (const Vec &a, const Vec &b) {return Vec(a.x+b.x, a.y+b.y);}
inline Vec operator - (const Vec &a, const Vec &b) {return Vec(a.x-b.x, a.y-b.y);}
template<typename T> inline Vec operator * (const Vec &a, T b) {return Vec(a.x*b, a.y*b);}
template<typename T> inline Vec operator * (T a, const Vec &b) {return Vec(a*b.x, a*b.y);}
inline Vec operator / (const Vec &a, double b) {return Vec(a.x/b, a.y/b);}
inline double dot(const Vec &a, const Vec &b) {return a.x*b.x + a.y*b.y;}
inline double cross(const Vec &a, const Vec &b) {return a.x*b.y - a.y*b.x;}
typedef Vec Poi;
inline bool angle_cmp(Poi a, Poi b) {return a.angle < b.angle;}
inline bool gt0(double x) {return x-eps>0;}
int n;
Poi a[N];
ll ans;
int main(){
read(n);
rep(i, 1, n) {read(a[i].x); read(a[i].y); a[i].cal_angle();}
sort(a+1, a+1+n, angle_cmp);
int last = 1, cnt = 0;
rep(i, 1, n){
while ((last%n+1 != i) && gt0(cross(a[i], a[last%n+1]))) last++, cnt++;
ans += 1ll * cnt * (cnt-1) / 2;
cnt--;
}
printf("%lld\n", 1ll*n*(n-1)*(n-2)/6 - ans);
return 0;
}
点集凹四边形计数
给一个点集,统计凹四边形的数量
解:
枚举中间凹点,转化为点集三角形覆盖计数问题
(BZOJ1913)
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define MS(_) memset(_, 0, sizeof(_))
#define MP make_pair
#define PB push_back
#define debug(...) fprintf(stderr, __VA_ARGS__)
template<typename T> inline void read(T &x){
x = 0; T f = 1; char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
x *= f;
}
typedef long long ll;
const int N = 5555;
struct Vec{
double x, y, angle;
Vec() {}
Vec(double _x, double _y):x(_x), y(_y) {angle = atan2(y, x);}
friend double atan2(Vec a){return atan2(a.y, a.x);}
};
inline Vec operator + (const Vec &a, const Vec &b) {return Vec(a.x+b.x, a.y+b.y);}
inline Vec operator - (const Vec &a, const Vec &b) {return Vec(a.x-b.x, a.y-b.y);}
template<typename T> inline Vec operator * (const Vec &a, T b) {return Vec(a.x*b, a.y*b);}
template<typename T> inline Vec operator * (T a, const Vec &b) {return Vec(a*b.x, a*b.y);}
inline Vec operator / (const Vec &a, double b) {return Vec(a.x/b, a.y/b);}
inline double dot(const Vec &a, const Vec &b) {return a.x*b.x + a.y*b.y;}
inline double cross(const Vec &a, const Vec &b) {return a.x*b.y - a.y*b.x;}
typedef Vec Poi;
inline bool angle_cmp(Vec a, Vec b) {return a.angle<b.angle;}
ll ans1, ans2, n;
Vec p[N], a[N];
inline ll solve(int k){
ll tot = 1ll*(n-1)*(n-2)*(n-3)/6;
int len = 0;
for (int i = 1; i <= n; i++)
if (i != k) p[++len] = a[i]; else p[0] = a[i];
rep(i, 1, len) p[i] = p[i]-p[0];
sort(p+1, p+1+len, angle_cmp);
for (int i = 1, r = 1, t = 0; i <= len; i++){
if (r%len+1 == i) r++, t++;
while ((r%len+1 != i) && (cross(p[i], p[r%len+1]) >= 0)) r++, t++;
tot -= 1ll*t*(t-1)/2;
t--;
}
return tot;
}
int main(){
read(n);
rep(i, 1, n) read(a[i].x), read(a[i].y);
rep(i, 1, n) ans1 += solve(i);
ans2 = 1ll*n*(n-1)*(n-2)*(n-3)/24 - ans1;
double ans = 2*ans2+ans1;
ans /= 1ll*n*(n-1)*(n-2)/6; ans += 3;
printf("%.6lf\n", ans);
return 0;
}
点集三角形面积和
给一个点集,求所有以点集里的点为顶点的三角形的面积和
解:
固定一条边,考虑剩下的一个点,将叉积式子展开发现只要维护一个和就行了
(BZOJ1132)
最小圆覆盖
给一个点集,求一个圆使得所有点被覆盖且圆最小
解:
随机增量法,参见这里http://wenku.baidu.com/view/162699d63186bceb19e8bbe6.html
(BZOJ2823)
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-6;
const int N = 1000000+10;
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define MS(_) memset(_, 0, sizeof(_))
#define MP make_pair
#define PB push_back
#define debug(...) fprintf(stderr, __VA_ARGS__)
struct Vec{
double x, y;
Vec() {}
Vec(double _x, double _y) : x(_x), y(_y) {}
inline double len() const{return sqrt(x*x+y*y);}
};
inline Vec operator + (const Vec &a, const Vec &b){return Vec(a.x+b.x,a.y+b.y);}
inline Vec operator - (const Vec &a, const Vec &b){return Vec(a.x-b.x,a.y-b.y);}
template<typename T> inline Vec operator * (const Vec &a, T b){return Vec(a.x*b,a.y*b);}
template<typename T> inline Vec operator * (T a, const Vec &b){return Vec(a*b.x,a*b.y);}
template<typename T> inline Vec operator / (const Vec &a, T b){return Vec(a.x/b,a.y/b);}
inline double dot (const Vec &a, const Vec &b){return a.x*b.x+a.y*b.y;}
inline double cross (const Vec &a, const Vec &b){return a.x*b.y-a.y*b.x;}
typedef Vec Poi;
inline bool gt(double x, double y) {return x-y>eps;}
inline bool eq0(double x) {return abs(x)<=eps;}
inline bool lt0(double x) {return x<-eps;}
int n;
Poi p[N], O;
double r;
inline double sqr(double x) {return x*x;}
inline Poi solve(Poi a, Poi b, Poi c){
Poi A = 2*Vec(b.x-a.x, c.x-b.x);
Poi B = 2*Vec(b.y-a.y, c.y-b.y);
Poi C = Vec(sqr(b.len())-sqr(a.len()), sqr(c.len())-sqr(b.len()));
double x = cross(C, B), y = cross(C, A), M = cross(A, B);
return Vec(x,-y)/M;
}
int main(){
scanf("%d", &n);
rep(i, 1, n) scanf("%lf%lf", &p[i].x, &p[i].y);
O = p[1]; r = 0;
rep(i, 2, n) if (gt((p[i]-O).len(), r)){
O = p[i]; r = 0;
rep(j, 1, i-1) if (gt((p[j]-O).len(), r)){
O = (p[i]+p[j])/2; r = (p[j]-O).len();
rep(k, 1, j-1) if (gt((p[k]-O).len(), r)){
Poi a = p[i], b = p[j], c = p[k];
if (eq0(cross(b-a, c-b))){
if (lt0(dot(c-a, b-a))) a = c;
else if(lt0(dot(c-b, a-b))) b = c;
O = (a+b)/2; r = (O-a).len();
}else{ O = solve(a, b, c); r = (O-a).len(); }
}
}
}
printf("%.2lf %.2lf %.2lf\n", O.x, O.y, r);
return 0;
}
最小矩形覆盖
给一个点集,求一个矩形使所有点被覆盖且矩形面积最小
解:
显然矩形一定有一条边是凸包上的边,旋转卡壳枚举这条边即可
(BZOJ1815)
点集最大矩形
给一个点集,求以点集里四个点为顶点的最大矩形面积
解:
考虑两条线段,它们能成为一个矩形的两条对角线当且仅当它们长度相同且中点重合,枚举所有线段,按长度排序,相同长度按中心位置排序,扫一遍即可知道答案。
(BZOJ2338)
点集最大四边形
给一个点集,求以点集里四个点为顶点的最大四边形面积
解:
显然这些点应该都在这个点集的凸包上,我们求出凸包,枚举四边形对角线上的顶点
(BZOJ1069)
//By Hachiman
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define REP(i, n) for (int i = 0; i < (n); i++)
#define PER(i, n) for (int i = (n)-1; ~i; i--)
#define EREP(p, x) for (Edge *p = g[x]; p; p = p->nxt)
#define NEREP(p, x) for (Ede *&p = cur[x]; p; p = p->nxt)
#define MS(_) memset(_, 0, sizeof(_))
#define MP make_pair
#define PB push_back
#define FT first
#define SC second
#ifdef Hachiman
# define debug(...) fprintf(stderr, __VA_ARGS__)
#else
# define debug(...)
#endif
#define RND(l, r) rand()%((r)-(l)+1)+(l)
typedef long long ll;
typedef long double ld;
typedef unsigned int ui;
typedef pair<int, int> PII;
const int INF = 0x7fffffff;
const double eps = 1e-8;
const int MOD = 1000000007;
template<typename T> inline void read(T &x){
x = 0; T f = 1; char ch = getchar();
while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
while (isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
x *= f;
}
template<typename T> inline void ckmax(T &a, T b){ if (a < b) a = b; }
template<typename T> inline void ckmin(T &a, T b){ if (a > b) a = b; }
template<typename T> inline void CKmax(T &a, T b){ if (a < b) { a = b; return 1;} return 0; }
template<typename T> inline void CKmin(T &a, T b){ if (a > b) { a = b; return 1;} return 0; }
inline bool eq(double x, double y){ return fabs(x-y) < eps; }
inline bool ge0(double x){ return x>=-eps; }
inline bool le0(double x){ return x<=eps; }
inline bool gt0(double x){ return x>-eps; }
inline bool lt0(double x){ return x<eps; }
struct Vec{
double x, y;
Vec(){}
Vec(double X, double Y):x(X), y(Y){}
};
inline bool operator < (const Vec &a, const Vec &b){ if (eq(a.x, b.x)) return a.y<b.y; return a.x<b.x; }
inline Vec operator + (const Vec &a, const Vec &b){ return Vec(a.x+b.x, a.y+b.y); }
inline Vec operator - (const Vec &a, const Vec &b){ return Vec(a.x-b.x, a.y-b.y); }
template<typename T> inline Vec operator * (const Vec &a, T b){ return Vec(a.x*b, a.y*b); }
template<typename T> inline Vec operator * (T b, const Vec &a){ return Vec(a.x*b, a.y*b); }
template<typename T> inline Vec operator / (const Vec &a, T b){ return Vec(a.x/b, a.y/b); }
inline double cross(const Vec &a, const Vec &b){ return a.x*b.y-b.x*a.y; }
inline double dot(const Vec &a, const Vec &b){ return a.x*b.x+a.y*b.y; }
typedef Vec Poi;
const int MaxN = 3000;
int n, r, head;
Poi CH[MaxN<<1], p[MaxN<<1];
double ans;
inline void ConvexHull(){
static Poi stack[MaxN]; int top = 0;
rep(i, 1, n){
while (top >= 2 && ge0(cross(stack[top]-stack[top-1], p[i]-stack[top]))) top--;
stack[++top] = p[i];
}
rep(i, 1, top) CH[++r] = stack[i]; top = 0;
rep(i, 1, n){
while (top >= 2 && le0(cross(stack[top]-stack[top-1], p[i]-stack[top]))) top--;
stack[++top] = p[i];
}
per(i, top-1, 2) CH[++r] = stack[i]; top = 0;
}
inline void RotatingCalipers(){
Poi *p1, *p2, *p3, *p4;
for (int i = r; i; i--, CH[++r] = CH[++head]){
p1 = &CH[head+1]; p2 = p1+2; p3 = p1+1; p4 = p2+1;
for (CH[r+1] = CH[head+1]; p2-CH<r; p2++){
while (lt0(cross(*(p3+1)-*p3, *p2-*p1))) p3++;
while (lt0(cross(*(p4+1)-*p4, *p1-*p2))) p4++;
ckmax(ans, cross(*p4-*p3, *p2-*p1)/2);
}
}
}
int main(int argc, char *argv[]){
read(n);
rep(i, 1, n) scanf("%lf%lf", &p[i].x, &p[i].y);
sort(p+1, p+1+n);
ConvexHull();
RotatingCalipers();
printf("%.3lf\n", ans);
return 0;
}
圆的周长并
给一些相互覆盖的圆,求最后能看见的轮廓线总长
解:
考虑一个圆对最终答案的贡献,一个圆的可见部分必然是若干连续的极角区间。我们求出该圆与其它所有圆相交的极角区间,做一遍区间并即可
(BZOJ1043)
//By Hachiman
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define MP make_pair
#define FT first
#define SC second
typedef long double ld;
const double eps = 1e-8;
const double pi = acos(-1.);
template<typename T> inline void read(T &x){
x = 0; T f = 1; char ch = getchar();
while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
while (isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
x *= f;
}
template<typename T> inline void ckmax(T &a, T b){ if (a < b) a = b; }
template<typename T> inline void ckmin(T &a, T b){ if (a > b) a = b; }
template<typename T> inline bool CKmax(T &a, T b){ if (a < b) { a = b; return 1;} return 0; }
template<typename T> inline bool CKmin(T &a, T b){ if (a > b) { a = b; return 1;} return 0; }
inline bool gt(double x, double y = 0.){ return x-y>-eps; }
inline bool lt(double x, double y = 0.){ return x-y<eps; }
inline bool ge(double x, double y = 0.){ return x-y>=-eps; }
inline bool le(double x, double y = 0.){ return x-y<=eps; }
inline bool eq(double x, double y = 0.){ return fabs(x-y)<=eps; }
const int MaxN = 1010;
struct Vec{
double x, y;
Vec(){}
Vec(double X, double Y):x(X), y(Y){}
inline double len() const{ return sqrt(x*x+y*y); }
};
inline Vec operator - (const Vec &a, const Vec &b){ return Vec(a.x-b.x, a.y-b.y); }
inline double Distance(const Vec &a, const Vec &b){ Vec c = a-b; return c.len(); }
typedef Vec Poi;
struct Circle{ Poi O; double r; }circle[MaxN];
pair<double, double> Interval[MaxN];
int n, tot;
double ans;
inline void GetIntersection(Circle O1, Circle O2, double dis){
double alpha = atan2(O2.O.y-O1.O.y, O2.O.x-O1.O.x)+pi, // alpha /in (0, 2pi]
beta = acos((O1.r*O1.r+dis*dis-O2.r*O2.r)/(2*O1.r*dis)); //beta /in (0, pi]
pair<double, double> tmp = MP(alpha-beta, alpha+beta);
if (ge(tmp.FT) && le(tmp.SC, 2*pi)) Interval[++tot] = tmp;
else if (lt(tmp.FT)){ Interval[++tot] = MP(tmp.FT+2*pi, 2*pi); Interval[++tot] = MP(0, tmp.SC); }
else if (gt(tmp.SC, 2*pi)){ Interval[++tot] = MP(tmp.FT, 2*pi); Interval[++tot] = MP(0, tmp.SC-2*pi); }
}
inline double IntervalUnion(){
double res = 0., L = -1., R = -1.;
sort(Interval+1, Interval+1+tot);
rep(i, 1, tot){
if (gt(Interval[i].FT, R)) res += R-L, L = Interval[i].FT, R = Interval[i].SC;
else if (gt(Interval[i].SC, R)) R = Interval[i].SC;
}
res += R-L;
return 2*pi-res;
}
int main(int argc, char *argv[]){
read(n);
per(i, n, 1) scanf("%lf%lf%lf", &circle[i].r, &circle[i].O.x, &circle[i].O.y);
rep(i, 1, n){
tot = 0;
try{
rep(j, 1, i-1){
double dis = Distance(circle[i].O, circle[j].O);
if (gt(circle[j].r-circle[i].r, dis)) throw(false);
if (gt(circle[i].r+circle[j].r, dis) && lt(fabs(circle[i].r-circle[j].r), dis))
GetIntersection(circle[i], circle[j], dis);
}
}catch(bool){ continue; }
ans += IntervalUnion()*circle[i].r;
}
printf("%.3lf\n", ans);
return 0;
}
曼哈顿距离
曼哈顿距离可以这样定义:
定义1:平面上两个点
定义2:一个点与周围四连通的点的距离都为
1
切比雪夫距离
切比雪夫距离可以这样定义:
定义1:平面上两个点
定义2:一个点与周围八连通的点的距离都为
1
对于一个点集,它们之间的切比雪夫距离可以通过将
三角形面积并
给一些三角形,求它们的面积并
解:
将所有线段的交点都取出来,按
x
排序并
(BZOJ1845)
//By Hachiman
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define REP(i, n) for (int i = 0; i < (n); i++)
#define PER(i, n) for (int i = (n)-1; ~i; i--)
#define EREP(p, x) for (Edge *p = g[x]; p; p = p->nxt)
#define NEREP(p, x) for (Ede *&p = cur[x]; p; p = p->nxt)
#define MS(_) memset(_, 0, sizeof(_))
#define MP make_pair
#define PB push_back
#define FT first
#define SC second
#ifdef Hachiman
# define debug(...) fprintf(stderr, __VA_ARGS__)
#else
# define debug(...)
#endif
#define RND(l, r) rand()%((r)-(l)+1)+(l)
typedef long long ll;
typedef long double ld;
typedef unsigned int ui;
typedef pair<int, int> PII;
const ld INF = 1e18;
const ld eps = 1e-8;
template<typename T> inline void read(T &x){
x = 0; T f = 1; char ch = getchar();
while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
while (isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
x *= f;
}
template<typename T> inline void ckmax(T &a, T b){ if (a < b) a = b; }
template<typename T> inline void ckmin(T &a, T b){ if (a > b) a = b; }
template<typename T> inline bool CKmax(T &a, T b){ if (a < b) { a = b; return 1;} return 0; }
template<typename T> inline bool CKmin(T &a, T b){ if (a > b) { a = b; return 1;} return 0; }
inline bool gt(ld x, ld y = 0.){ return x>y+eps; }
inline bool lt(ld x, ld y = 0.){ return x<y-eps; }
inline bool ge(ld x, ld y = 0.){ return x>=y-eps; }
inline bool le(ld x, ld y = 0.){ return x<=y+eps; }
inline bool eq(ld x, ld y = 0.){ return fabs(x-y)<=eps; }
const int MaxN = 510;
struct Vec{
ld x, y;
Vec(){}
Vec(ld X, ld Y):x(X), y(Y){}
void set(){ ld X, Y; cin >> X >> Y; x = X; y = Y; }
}p[MaxN*MaxN];
inline bool operator < (const Vec &a, const Vec &b){ return lt(a.x,b.x)||(eq(a.x,b.x)&<(a.y,b.y)); }
inline Vec operator + (const Vec &a, const Vec &b){ return Vec(a.x+b.x, a.y+b.y); }
inline Vec operator - (const Vec &a, const Vec &b){ return Vec(a.x-b.x, a.y-b.y); }
template<typename T> inline Vec operator * (const Vec &a, T b){ return Vec(a.x*b, a.y*b); }
template<typename T> inline Vec operator * (T b, const Vec &a){ return Vec(a.x*b, a.y*b); }
template<typename T> inline Vec operator / (const Vec &a, T b){ return Vec(a.x/b, a.y/b); }
inline ld dot(const Vec &a, const Vec &b){ return a.x*b.x+a.y*b.y; }
inline ld cross(const Vec &a, const Vec &b){ return a.x*b.y-b.x*a.y; }
typedef Vec Poi;
struct Triangle{
Poi dot[3];
void set(){ REP(i, 3) dot[i].set(); }
}T[MaxN];
struct Line{
Poi op, ed;
Line(){}
Line(Poi A, Poi B):op(A), ed(B){}
}line[MaxN][3];
int n, tot;
pair<ld, ld> Interval[MaxN];
inline bool Intersect(const Line &a, const Line &b){
ld c1 = cross(b.ed-b.op,a.ed-b.op), c2 = cross(b.ed-b.op,a.op-b.op);
ld c3 = cross(a.ed-a.op,b.ed-a.op), c4 = cross(a.ed-a.op,b.op-a.op);
return lt(c1*c2)&<(c3*c4);
}
inline Poi GetIntersection(const Line &a, const Line &b){
return b.op+(b.ed-b.op)*cross(b.op-a.op,a.ed-a.op)/cross(a.ed-a.op,b.ed-b.op);
}
int main(int argc, char *argv[]){
freopen("hehe.in", "r", stdin);
freopen("hehe.out", "w", stdout);
read(n);
rep(i, 1, n){
T[i].set(); REP(j, 3) p[++tot] = T[i].dot[j];
sort(T[i].dot, T[i].dot+3);
if (gt(cross(T[i].dot[2]-T[i].dot[0],T[i].dot[1]-T[i].dot[0])))
line[i][0]=Line(T[i].dot[0],T[i].dot[2]),line[i][1]=Line(T[i].dot[2],T[i].dot[1]),line[i][2]=Line(T[i].dot[1],T[i].dot[0]);
else
line[i][0]=Line(T[i].dot[2],T[i].dot[0]),line[i][1]=Line(T[i].dot[0],T[i].dot[1]),line[i][2]=Line(T[i].dot[1],T[i].dot[2]);
}
rep(i, 1, n) rep(j, 1, i-1) REP(x, 3) REP(y, 3)
if (Intersect(line[i][x], line[j][y])) p[++tot] = GetIntersection(line[i][x], line[j][y]);
sort(p+1, p+1+tot);
ld ans = 0;
rep(i, 2, tot){ Line T = Line(Vec((p[i-1].x+p[i].x)/2, -INF), Vec((p[i-1].x+p[i].x)/2, INF));
int cnt = 0;
rep(j, 1, n) if (Intersect(T, line[j][0])){
Poi bottom = GetIntersection(T, line[j][0]),
top = GetIntersection(T, line[j][Intersect(T, line[j][1])?1:2]);
if (top < bottom) swap(top, bottom);
Interval[++cnt] = MP(bottom.y, top.y);
}
ld L = -1., R = -1., sum = 0.;
sort(Interval+1, Interval+1+cnt);
rep(j, 1, cnt){
if (gt(Interval[j].FT, R)) sum += R-L, L = Interval[j].FT, R = Interval[j].SC;
else if (gt(Interval[j].SC, R)) R = Interval[j].SC;
}
sum += R-L;
ans += (p[i].x-p[i-1].x)*sum;
}
cout<<fixed<<setprecision(2)<<ans-eps<<endl;
return 0;
}
平面最短周长三角形
给一个点集,求以点集里的点为顶点的最小周长三角形
解:
1.记录全局答案
ans
2.将所有点按照
x
值排序
3.定义
4.对于每层
Solve(l,r)
,将当前区间分成左右两部分,分别递归处理
5.两侧的最小三角形都以处理完毕,现在我们要处理的就是两区间之间的点构成的三角形
6.将本层中与点
mid
的横坐标之差不超过
ans/2
的点拎出来,按照纵坐标排序 (其实这步可以直接递归退出时归并排序)
7.维护双指针,保证内部纵坐标之差不超过
ans/2
,对于每个点在范围内暴力查找最小三角形即可
//By Hachiman
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define REP(i, n) for (int i = 0; i < (n); i++)
#define PER(i, n) for (int i = (n)-1; ~i; i--)
#define EREP(p, x) for (Edge *p = g[x]; p; p = p->nxt)
#define NEREP(p, x) for (Ede *&p = cur[x]; p; p = p->nxt)
#define MS(_) memset(_, 0, sizeof(_))
#define MP make_pair
#define PB push_back
#define FT first
#define SC second
#ifdef Hachiman
# define debug(...) fprintf(stderr, __VA_ARGS__)
#else
# define debug(...)
#endif
#define RND(l, r) rand()%((r)-(l)+1)+(l)
typedef long long ll;
typedef long double ld;
typedef unsigned int ui;
typedef pair<int, int> PII;
const int INF = 0x7fffffff;
const double eps = 1e-8;
const int MOD = 1000000007;
template<typename T> inline void read(T &x){
x = 0; T f = 1; char ch = getchar();
while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); }
while (isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
x *= f;
}
template<typename T> inline void ckmax(T &a, T b){ if (a < b) a = b; }
template<typename T> inline void ckmin(T &a, T b){ if (a > b) a = b; }
template<typename T> inline bool CKmax(T &a, T b){ if (a < b) { a = b; return 1;} return 0; }
template<typename T> inline bool CKmin(T &a, T b){ if (a > b) { a = b; return 1;} return 0; }
const int MaxN = 200100;
struct Vec{
int x, y;
Vec(){}
Vec(int X, int Y):x(X), y(Y){}
inline void set(){ int X, Y; read(X); read(Y); x = X; y = Y; }
inline double len() const{ return sqrt(1.0*x*x+1.0*y*y); }
}p[MaxN], P[MaxN];
inline bool operator < (const Vec &a, const Vec &b){ return a.x<b.x||(a.x==b.x&&a.y<b.y); }
inline Vec operator - (const Vec &a, const Vec &b){ return Vec(a.x-b.x, a.y-b.y); }
inline double Distance(const Vec &a, const Vec &b){ Vec c = a-b; return c.len(); }
int n;
double ans = 1e18;
inline void DivideAndConquer(int l, int r){
if (l == r) return;
if (l + 1 == r){ if (p[l].y > p[r].y) swap(p[l], p[r]); return; }
int mid = l+r >> 1, T = p[mid].x;
DivideAndConquer(l, mid); DivideAndConquer(mid+1, r);
int l1 = l, l2 = mid+1;
rep(i, l, r){
if ((l2>r) || (l1<=mid&&p[l1].y<p[l2].y)) P[i] = p[l1++];
else P[i] = p[l2++];
}
rep(i, l, r) p[i] = P[i];
for (int i = l, tail = l; i <= r; i++) if (abs(p[i].x-T)<ans/2){
for (; p[i].y-p[tail].y>ans/2; tail++);
for (int j = tail; j < i-1; j++) if (abs(p[j].x-T)<ans/2)
rep(k, j+1, i-1) ckmin(ans, Distance(p[i],p[j])+Distance(p[j],p[k])+Distance(p[k],p[i]));
}
}
int main(int argc, char *argv[]){
read(n);
rep(i, 1, n) p[i].set();
sort(p+1, p+1+n);
DivideAndConquer(1, n);
printf("%.6lf\n", ans);
return 0;
}