Andrew:
int n;
struct point {
double x, y;
point(){}
point(double X, double Y) { x = X, y = Y; }
point operator - (const point &A) { return point(x-A.x, y-A.y); }
bool operator < (const point &A)const {
if(x == A.x) return y < A.y;
return x < A.x;
}
} a[maxn], pa[maxn];
int dcmp(double x){
if(fabs(x) < eps) return 0;
return x < 0 ? -1 : 1;
}
double cross(point a, point b) { // 叉积
return a.x*b.y - b.x*a.y;
}
double getd(point a, point b) { // 两点距离
return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
int andrew(point *P, int n, point *S) { // P为点集合, A为凸包点
sort(P, P+n);
int tp = 0;
for(int i=0; i<n; i++) { // 下凸包
while(tp>1 && dcmp(cross(S[tp-1]-S[tp-2], P[i]-S[tp-2]))<=0) tp--;
S[tp++] = P[i];
}
for(int i=n-2, k=tp; ~i; i--) { // 上凸包
while(tp>k && dcmp(cross(S[tp-1]-S[tp-2], P[i]-S[tp-2]))<=0) tp--;
S[tp++] = P[i];
}
return n > 1 ? tp - 1 : tp;
}
int main() {
while(~scanf("%d", &n) && n){
for(int i=0; i<n; i++) scanf("%lf%lf", &a[i].x, &a[i].y);
int tp = andrew(a, n, pa);
double ans = 0;
for(int i=0; i<tp-1; i++) ans += getd(pa[i], pa[i+1]);
ans += getd(pa[0], pa[tp-1]);
if(n == 2) ans = getd(pa[0], pa[1]);
printf("%.2f\n", ans);
}
}
Graham:
int tp, n;
struct point {
double x, y;
point(){}
point(double X, double Y) { x = X, y = Y; }
point operator - (const point &A) { return point(x-A.x, y-A.y); }
bool operator < (const point &A)const {
if(x == A.x) return y < A.y;
return x < A.x;
}
} a[maxn], pa[maxn];
int dcmp(double x){
if(fabs(x) < eps) return 0;
return x < 0 ? -1 : 1;
}
double cross(point a, point b) { // 叉积
return a.x*b.y - a.x*b.y;
}
double getd(point a, point b) { // 两点距离
return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
bool gcmp(point A, point B) { // 极角排序
double tmp = cross(A-a[0], B-a[0]);
if(dcmp(tmp) > 0) return true;
if(dcmp(tmp)==0 && dcmp(getd(A,a[0])-getd(B,a[0]))<0) return true;
return false;
}
void graham(){
sort(a+1, a+n, gcmp);
tp = 0;
for(int i=0; i<n; i++){
while(tp>1 && dcmp(cross(pa[tp-1]-pa[tp-2], a[i]-pa[tp-2]))<=0) tp--;
pa[tp++] = a[i];
}
}
int main() {
while(~scanf("%d", &n) && n){
for(int i=0; i<n; i++) scanf("%lf%lf", &a[i].x, &a[i].y);
int p0 = 0;
for(int i=1; i<n; i++) if(a[i] < a[p0]) p0 = i;
swap(a[0], a[p0]);
graham();
double ans = 0;
for(int i=0; i<tp-1; i++) ans += getd(pa[i], pa[i+1]);
ans += getd(pa[0], pa[tp-1]);
if(n == 2) ans = getd(pa[0], pa[1]);
printf("%.2f\n", ans);
}
}
int n;
struct point {
double x, y;
point() {}
point(double X, double Y) { x = X, y = Y; }
point operator - (const point &A) { return point(x-A.x, y-A.y); }
bool operator < (const point &A)const {
if(x == A.x) return y < A.y;
return x < A.x;
}
} a[maxn], pa[maxn];
double xmult(point a, point b, point c) {
return cross(a-c, b-c);
}
int rotating_calipers(int tp) {
int q = 1; double ret = 0;
// pa[++tp] = pa[0];
for(int i=0; i<tp; i++) {
while(xmult(pa[i], pa[i+1], pa[(q+1)%tp]) > xmult(pa[i], pa[i+1], pa[q]))
q = (q + 1) % tp;
ret = max(ret, getd2(pa[i], pa[q]));
// ret = max(ret, max(getd2(pa[i], pa[q]), getd2(pa[i+1], pa[q])));
}
return ret;
}
int main() {
scanf("%d", &n);
for(int i=0; i<n; i++) scanf("%lf%lf", &a[i].x, &a[i].y);
int tp = andrew(a, n, pa);
printf("%d\n", rotating_calipers(tp));
}
int n;
struct point {
double x, y;
point(){}
point(double X, double Y) { x = X, y = Y; }
point operator - (const point &A) { return point(x-A.x, y-A.y); }
bool operator < (const point &A)const {
if(x == A.x) return y < A.y;
return x < A.x;
}
} a[maxn], pa[maxn];
double rotating_calipers(int tp){
int p = 1, q = 2; double ret = 0;
// pa[++tp] = pa[0];
for(int i=0; i<tp; i++){
while(xmult(pa[i], pa[p], pa[(q+1)%tp]) > xmult(pa[i], pa[p], pa[q]))
q = (q + 1) % tp; // i,p 固定,旋转 q
ret = max(ret, xmult(pa[i], pa[p], pa[q]));
while(xmult(pa[i], pa[(p+1)%tp], pa[q]) > xmult(pa[i], pa[p], pa[q]))
p = (p + 1) % tp; // i,q 固定,旋转 p
ret = max(ret, xmult(pa[i], pa[p], pa[q]));
}
return ret;
}
int main() {
while(~scanf("%d", &n) && n!=-1){
for(int i=0; i<n; i++) scanf("%lf%lf", &a[i].x, &a[i].y);
int tp = andrew(a, n, pa);
printf("%.2f\n", 0.5 * rotating_calipers(tp));
}
}
判断凸包相交的两个必要条件:
①
①
① 一个凸包上的所有点不在另一个凸包内或边上
②
②
② 两个凸包没有线段相交
int cnt1, cnt2, k1, k2;
struct point {
double x, y;
point() {}
point(double X, double Y) { x = X, y = Y; }
point operator - (const point &A) { return point(x-A.x, y-A.y); }
bool operator < (const point &A)const {
if(x == A.x) return y < A.y;
return x < A.x;
}
} a[maxn], b[maxn], pa[maxn], pb[maxn];
inline int dcmp(double x) {
if(fabs(x) < eps) return 0;
return x < 0 ? -1 : 1;
}
inline double cross(point A, point B) { // 叉积
return A.x*B.y - B.x*A.y;
}
inline double dot(point A, point B) { // 点积
return A.x*B.x + B.y*A.y;
}
// 判断线段 AB是否跨立 MN
bool straddle(point A, point B, point M, point N) {
point p0 = { N.x - M.x , N.y - M.y }; // 向量 MN
point p1 = { A.x - M.x , A.y - M.y }; // 向量 MA
point p2 = { B.x - M.x , B.y - M.y }; // 向量 MB
return cross(p1, p0) * cross(p2, p0) <= 0;
}
// 判断 线段 AB为对角线构成的矩形 和 MN线段为对角线构成的矩形 是否存在重叠
bool overlap(point A, point B, point M, point N) {
point P = { max(min(A.x, B.x), min(M.x, N.x)), max(min(A.y, B.y), min(M.y, N.y))};
point Q = { min(max(A.x, B.x), max(M.x, N.x)), min(max(A.y, B.y), max(M.y, N.y))};
return P.x <= Q.x && P.y <= Q.y;
}
// 判断线段 AB和 MN是否相交
bool intersect(point A, point B, point M, point N) {
return straddle(A, B, M, N) && straddle(M, N, A, B) && overlap(A, B, M, N);
}
bool onsegment(point p, point A, point B) {
return dcmp( cross(A-p, B-p) ) == 0 && dcmp( dot(A-p, B-p) ) < 0;
}
int ispip(point p, point poly[], int n) { // 判断点是否在多边形类
int num = 0, k, d1, d2;
for(int i=0; i<n; i++) {
if(onsegment(p, poly[i], poly[(i+1)%n])) return -1; // 在边界上
k = dcmp(cross(poly[(i+1)%n]-poly[i], p-poly[i]));
d1 = dcmp(poly[i].y - p.y);
d2 = dcmp(poly[(i+1)%n].y - p.y);
if(k > 0 && d1 <= 0 && d2 > 0) num++;
if(k < 0 && d2 <= 0 && d1 > 0) num++;
}
return num & 1;
}
bool check() {
for(int i=0; i<k1; i++) if(ispip(pa[i], pb, k2) != 0) return false;
for(int i=0; i<k2; i++) if(ispip(pb[i], pa, k1) != 0) return false;
for(int i=0; i<k1; i++)
for(int j=0; j<k2; j++)
if(intersect(pa[i], pa[(i+1)%k1], pb[j], pb[(j+1)%k2]))
return false;
return true;
}
int main() {
int T, n; scanf("%d", &T);
while(T--) {
scanf("%d", &n); cnt1 = 0, cnt2 = 0;
for(int i=0; i<n; i++) {
double x1, x2, y;
scanf("%lf%lf%lf", &x1, &x2, &y);
if(y < 0) a[cnt1++] = point {x1, x2};
else b[cnt2++] = point {x1, x2};
}
k1 = andrew(a, cnt1, pa), k2 = andrew(b, cnt2, pb);
printf(check() ? "Successful!\n" : "Infinite loop!\n");
}
}
给出若干直线
y
=
k
x
+
b
y=kx+b
y=kx+b,当从上往下看时,求所有可见的直线
或者可以理解为一堆直线里 最上面的的那些直线
发现这些直线是下凸的,并且斜率递增
n
a
m
o
namo
namo求个下凸包即可,按照
k
k
k 从小到大,
b
b
b 从大到小的顺序 排序
设栈顶的两条直线为
q
[
t
a
i
l
−
1
]
q[tail-1]
q[tail−1] 和
q
[
t
a
i
l
]
q[tail]
q[tail],当前直线为
l
[
i
]
l[i]
l[i]
若
q
[
t
a
i
l
−
1
]
q[tail-1]
q[tail−1] 与
q
[
t
a
i
l
]
q[tail]
q[tail] 的交点为
x
1
x_1
x1,
q
[
t
a
i
l
]
q[tail]
q[tail] 与
l
[
i
]
l[i]
l[i] 的交点为
x
2
x_2
x2
若
x
1
>
=
x
2
x_1 >= x_2
x1>=x2,则可以弹栈了
特殊的,当斜率相等时,肯定截距越大越好
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
int n;
struct Line{
int k, b, id;
bool operator < (const Line &A) const {
return k==A.k ? b>A.b : k<A.k;
}
} l[maxn], q[maxn];
double find(Line x, Line y){
return 1.0 * (y.b - x.b) / (x.k - y.k);
}
signed main() {
scanf("%d", &n);
for(int i=1; i<=n; i++) scanf("%d%d", &l[i].k, &l[i].b), l[i].id = i;
sort(l+1, l+1+n);
int tail = 0;
for(int i=1; i<=n; i++){
if(l[i].k == l[i-1].k && i != 1) continue;
while(tail>1 && find(l[i], q[tail])<=find(q[tail-1], q[tail])) tail--;
q[++tail] = l[i];
}
vector <int> ans;
for(int i=1; i<=tail; i++) ans.push_back(q[i].id);
sort(ans.begin(), ans.end());
for(auto i : ans) printf("%d ", i);
}
附eps用法:
a = = b a == b a==b | f a b s ( a − b ) < e p s fabs(a-b) < eps fabs(a−b)<eps |
a ! = b a != b a!=b | f a b s ( a − b ) > e p s fabs(a-b) > eps fabs(a−b)>eps |
a < b a < b a<b | a − b < − e p s a - b < -eps a−b<−eps |
a < = b a <= b a<=b | a − b < e p s a - b < eps a−b<eps |
a > b a > b a>b | a − b > e p s a - b > eps a−b>eps |
a > = b a >= b a>=b | a − b > − e p s a - b > -eps a−b>−eps |
struct point {
double x, y;
friend point operator - (point a, point b) {
point tmp;
tmp.x = a.x - b.x;
tmp.y = a.y - b.y;
return tmp;
}
};
point get_pc(point p1, point p2, point p3) { // 求圆心
double a, b, c, d, e, f, r; point p;
a = 2*(p2.x-p1.x); b = 2*(p2.y-p1.y);
c = p2.x*p2.x + p2.y*p2.y - p1.x*p1.x - p1.y*p1.y;
d = 2*(p3.x-p2.x); e = 2*(p3.y-p2.y);
f = p3.x*p3.x + p3.y*p3.y - p2.x*p2.x - p2.y*p2.y;
p.x = (b*f-e*c) / (b*d-e*a); p.y = (d*c-a*f) / (b*d-e*a);
r = sqrt((p.x-p1.x)*(p.x-p1.x) + (p.y-p1.y)*(p.y-p1.y)); // 半径
return p;
}
double getdis(point a, point b) { // 两点距离
return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
double gets1(point a, point b, point c) { // 叉积求面积
return fabs((b.x-a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x))/2.0;
}
double gets2(double a, double b, double c) { // 三边求面积
double p = (a + b + c) / 2.0;
return sqrt(p * (p-a) * (p-b) * (p-c));
}
暴力枚举每两条线段的距离
但要对每条线段的左端点排序
若左侧线段的右端点
x
x
x 与右侧线段的左端点
x
x
x 差值大于了
a
n
s
ans
ans
则直接
b
r
e
a
k
break
break,这样竟然能优化
19
19
19 秒
struct point {
double x, y;
point() {}
point(double X, double Y) { x = X, y = Y; }
point operator - (const point &A) { return point(x-A.x, y-A.y); }
bool operator < (const point &A)const {
if(x == A.x) return y < A.y;
return x < A.x;
}
} ;
inline int dcmp(double x) {
if(fabs(x) < eps) return 0;
return x < 0 ? -1 : 1;
}
inline double cross(point A, point B) { // 叉积
return A.x*B.y - B.x*A.y;
}
inline double dot(point A, point B) { // 点积
return A.x*B.x + B.y*A.y;
}
double getdis(point a, point b) { // 两点距离
return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
struct Line {
point s, e;
Line() {}
Line(point S, point E) { s = S, e = E; }
double length() { return getdis(s, e); }
};
//点到直线距离
inline double point_to_line(point p, Line a) {
return fabs(cross(p-a.s, a.e-a.s) / a.length());
}
//点到线段距离
inline double point_to_seg(point p, Line a) {
if(dcmp(dot(p-a.s, a.e-a.s))<0 || dcmp(dot(p-a.e, a.s-a.e))<0)
return min(getdis(p, a.e), getdis(p, a.s));
return point_to_line(p, a);
}
//线段到线段的距离
inline double seg_to_seg(Line u, Line v) {
return min( min(point_to_seg(u.s, v), point_to_seg(u.e, v)),\
min( point_to_seg(v.s, u), point_to_seg(v.e, u)) );
}
bool cmp(const Line &u, const Line &v) {
return u.s < v.s;
}
const int maxn = 1e4 + 5;
int T, n;
Line line[maxn];
int main() {
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
for(int i=1; i<=n; i++) {
scanf("%lf%lf", &line[i].s.x, &line[i].s.y);
scanf("%lf%lf", &line[i].e.x, &line[i].e.y);
if(line[i].e < line[i].s) swap(line[i].s, line[i].e);
}
sort(line+1, line+1+n, cmp);
double ans = 1e10;
for(int i=1; i<=n; i++) {
for(int j=i+1; j<=n; j++) {
if(dcmp(line[j].s.x-line[i].e.x - ans) > 0) break;
ans = min(ans, seg_to_seg(line[i], line[j]));
}
}
printf("%.9f\n", ans);
}
}