看起来很挫的……
线段与直线
const int SZ = 150; const int INF = 1e9+10; const double eps = 1e-8; const double pi = acos(-1.0); int sgn(double x) { if(fabs(x) < eps) return 0; if(x < 0) return -1; return 1; } struct Point { double x, y; Point () {} Point (double x, double y) : x(x), y(y) {} Point operator +(const Point &a)const{ return Point(x + a.x, y + a.y); } Point operator -(const Point &a)const{ return Point(x - a.x, y - a.y); } bool operator ==(const Point &a)const{ if(sgn(x - a.x) == 0 && sgn(y - a.y) == 0) return true; return false; } bool operator !=(const Point &a)const{ return x != a.x || y != a.y; } bool operator <(const Point &a)const{ if(a.x != x) return x < a.x;//以x作为第一关键字排序 return y < a.y; } double operator *(const Point &a)const{//点乘 return x * a.x + y * a.y; } double operator ^(const Point &a)const{//叉乘 return x * a.y - y * a.x; } }p[SZ]; struct edge { Point s, e; }line[SZ]; double xmul(Point a, Point b, Point c) //ab * ac, xmul<0表示p0在se左 { return (b - a) ^ (c - a); } double getdis(Point a, Point b)//点a与点b之间的距离 { return sqrt((a-b) * (a-b)); } bool online(Point p, edge l)//p是否在线段l上 { return sgn((p-l.s) ^ (l.e-l.s)) == 0 && sgn((p-l.s) * (p-l.e)) <= 0; } bool checkcross(edge l1, edge l2)//判断直线l1是否与线段l2相交 { if(sgn(xmul(l2.s, l1.s, l1.e)) * sgn(xmul(l2.e, l1.s, l1.e)) <= 0) return true; return false; } bool onseg(edge l1, edge l2)//判断线段l1是否与线段l2共线但不重合 { int flag = 0; if(max(l1.s.x, l1.e.x) < min(l2.s.x, l2.e.x) || max(l2.s.x, l2.e.x) < min(l1.s.x, l1.e.x)) flag++; if(max(l1.s.y, l1.e.y) < min(l2.s.y, l2.e.y) || max(l2.s.y, l2.e.y) < min(l1.s.y, l1.e.y)) flag++; if(getk(l1.s, l1.e) - getk(l2.s, l2.e) == 0) flag++; if(flag == 3) return true; return false; } bool checksegcross(edge l1, edge l2)//判断线段l1是否与线段l2相交 { int flag = 0; if(((l2.e-l2.s) ^ (l1.s-l2.s)) * ((l2.e-l2.s) ^ (l1.e-l2.s)) <= 0) flag++; if(((l1.e-l1.s) ^ (l2.s-l1.s)) * ((l1.e-l1.s) ^ (l2.e-l1.s)) <= 0) flag++; if(!onseg(a, b)) flag++; if(flag == 3) return true; return false; }
求凸包:
bool cmp(Point a, Point b) { double tmp = xmul(p[0], a, b); if(sgn(tmp) < 0) return false; if(sgn(tmp) > 0) return true; return getdis(p[0], a) < getdis(p[0], b); } int n; double graham() { int k = 0; for(int i = 1; i < n; i++) if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i; swap(p[0], p[k]); sort(p+1, p+n, cmp); int top = 0; s[top++] = p[0]; s[top++] = p[1]; for(int i = 2;i < n;i ++) { while(top > 1 && ((s[top-1] - s[top-2]) ^ (p[i] - s[top-2])) < 0) top --; s[top++] = p[i]; } double ans = 0; for(int i = 0; i < top; i++) ans += getdis(s[i], i == top-1 ? s[0] : s[i+1]); return ans; }
POJ 1113
用墙围起来,墙距离原图形至少L距离
就是凸包的周长加上一个半径为L的圆
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <queue> using namespace std; const int SZ = 1100; const int INF = 1e9+10; const double eps = 1e-8; const double pi = acos(-1.0); int sgn(double x) { if(fabs(x) < eps) return 0; if(x < 0) return -1; return 1; } struct Point { double x, y; Point operator +(const Point &a)const{ return (Point){a.x + x, a.y + y}; } Point operator -(const Point &a)const{ return (Point){a.x - x, a.y - y}; } bool operator ==(const Point &a)const{ if(sgn(a.x - x) == 0 && sgn(a.y - y) == 0) return true; return false; } bool operator !=(const Point &a)const{ return a.x != x || a.y != y; } bool operator <(const Point &a)const{ if(a.x != x) return a.x < x; return a.y < y; } double operator *(const Point &a)const{ return a.x * x + a.y * y; } double operator ^(const Point &a)const{ return a.x * y - a.y * x; //return x * a.y - y * a.x; } }p[SZ], s[SZ]; double xmul(Point p0, Point p1, Point p2) //p0p1 * p0p2 xmul<0 p0在p1p2左 { return (p1 - p0) ^ (p2 - p0); } double getdis(Point a, Point b) { return sqrt((a-b) * (a-b)); } bool cmp(Point a, Point b) { double tmp = xmul(p[0], a, b); if(sgn(tmp) < 0) return false; if(sgn(tmp) > 0) return true; return getdis(p[0], a) < getdis(p[0], b); } int n; double graham() { int k = 0; for(int i = 1; i < n; i++) if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i; swap(p[0], p[k]); sort(p+1, p+n, cmp); int top = 0; s[top++] = p[0]; s[top++] = p[1]; for(int i = 2;i < n;i ++) { while(top > 1 && ((s[top-1] - s[top-2]) ^ (p[i] - s[top-2])) < 0) top --; s[top++] = p[i]; } double ans = 0; for(int i = 0; i < top; i++) ans += getdis(s[i], i == top-1 ? s[0] : s[i+1]); return ans; } int main() { int L; scanf("%d %d", &n, &L); for(int i = 0; i < n; i++) { int a, b; scanf("%d %d", &a, &b); p[i] = (Point){a, b}; } double ans = graham(); ans += pi * 2 * L; printf("%.0f ", ans); return 0; }
POJ 1696
题意:只能直走或者左转,最多能到达多少个点
思路:合理选择出发点肯定每个点都能到达,贪心的思想
每次选以上一个位置为极点,极角最小的点。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <queue> 7 using namespace std; 8 const int SZ = 150; 9 const int INF = 1e9+10; 10 const double eps = 1e-8; 11 const double pi = acos(-1.0); 12 int sgn(double x) 13 { 14 if(fabs(x) < eps) return 0; 15 if(x < 0) return -1; 16 return 1; 17 } 18 struct Point 19 { 20 int id; 21 double x, y; 22 Point operator -(const Point &a)const{ 23 return (Point){id, x - a.x, y - a.y}; 24 } 25 double operator *(const Point &a)const{ 26 return a.x * x + a.y * y; 27 } 28 double operator ^(const Point &b)const 29 { 30 return x*b.y - y*b.x; 31 } 32 }p[SZ]; 33 double xmul(Point p0, Point p1, Point p2) //p0p1 * p0p2 xmul<0 p0在p1p2左 34 { 35 return (p1 - p0) ^ (p2 - p0); 36 } 37 double getdis(Point a, Point b) 38 { 39 return sqrt((a-b) * (a-b)); 40 } 41 int idx;//标记上一个位置 为极点 42 bool cmp(Point a, Point b) 43 { 44 double tmp = xmul(p[idx], a, b); 45 if(sgn(tmp) < 0) return false; 46 if(sgn(tmp) > 0) return true; 47 return getdis(p[idx], a) < getdis(p[idx], b); 48 } 49 int main() 50 { 51 int T; 52 scanf("%d", &T); 53 while(T--) 54 { 55 int n, id; 56 scanf("%d", &n); 57 for(int i = 1; i <= n; i++) 58 scanf("%d %lf %lf", &p[i].id, &p[i].x, &p[i].y); 59 int k = 1; 60 for(int i = 2; i <= n; i++) 61 if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i; 62 swap(p[1], p[k]); 63 idx = 1; 64 for(int i = 2; i <= n; i++) 65 { 66 sort(p+i, p+1+n, cmp); 67 idx++; 68 } 69 printf("%d", n); 70 for(int i = 1; i <= n; i++) 71 printf(" %d", p[i].id); 72 printf(" "); 73 } 74 return 0; 75 }
HDU 6325
题意:每个点有一个标号,要求x坐标递增,代价为两个坐标的叉积。 求起点到终点总代价最小的飞行路线,并输出字典序最小的路线
思路:因为凸包是求逆时针的时候面积包住所有点的面积最大,那么我们题目这样是顺时针,相反的就是面积最小,所以这题就是求顺时针的凸包,那肯定就包括起点、终点、凸包的拐点了,只要把上凸包求出来就好
就是改一下cmp和求凸包的时候的更新函数
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <queue> using namespace std; const int SZ = 200200; const int INF = 1e9+10; const double eps = 1e-8; const double pi = acos(-1.0); #define getT int T;scanf("%d", &T); while(T--) int sgn(double x) { if(fabs(x) < eps) return 0; if(x < 0) return -1; return 1; } struct Point { double x, y; int id; Point () {} Point (double x, double y) : x(x), y(y) {} Point operator -(const Point &a)const{ return (Point){x - a.x, y - a.y}; } double operator *(const Point &a)const{//点乘 return x * a.x + y * a.y; } double operator ^(const Point &a)const{//叉乘 return x * a.y - y * a.x; } }p[SZ]; double xmul(Point a, Point b, Point c) //ab * ac, xmul<0表示p0在se左 { return (b - a) ^ (c - a); } int n; bool cmp(Point a, Point b) { if(a.x != b.x) return a.x < b.x; return a.id > b.id; } int top; int s[SZ]; void graham() { top = 0; sort(p+1, p+n+1, cmp); s[++top] = 1; s[++top] = 2; for(int i = 3; i <= n; i++) { while(top > 1) { int x = s[top]; top--; int y = s[top]; if(xmul(p[y], p[i], p[x]) > 0 || (xmul(p[y], p[i], p[x]) == 0 && p[i].id > p[x].id)) { s[++top] = x; break; } } s[++top] = i; } } int main() { getT { scanf("%d", &n); for(int i = 1; i <= n; i++) { double x, y; scanf("%lf %lf", &x, &y); p[i] = Point(x, y); p[i].id = i; } graham(); printf("%d", p[s[1]].id); for(int i = 2; i <= top; i++) printf(" %d", p[s[i]].id); printf(" "); } return 0; }
BZOJ 1007
给出n条形如y = kx + b的直线,求从y轴正无穷向下看能看到哪些直线
·三维凸包
HDU 3662 模板。。很强
#include <iostream> #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <queue> using namespace std; const int SZ = 320; const int INF = 1e9+10; const double eps = 1e-8; const double pi = acos(-1.0); int sgn(double x) { if(fabs(x) < eps) return 0; if(x < 0) return -1; return 1; } struct Point { double x, y, z; Point () {} Point (double x, double y, double z) : x(x), y(y), z(z) {} Point operator -(const Point &a)const{ return Point(x - a.x, y - a.y, z - a.z); } double operator *(const Point &a)const{//点乘 return x * a.x + y * a.y + z * a.z; } Point operator ^(const Point &a)const{//叉乘 return Point(y * a.z - z * a.y, z * a.x - x * a.z, x * a.y - y * a.x); } }p[SZ]; Point xmul(Point a, Point b, Point c) //ab * ac, xmul<0表示p0在se左 { return (b - a) ^ (c - a); } double getdis(Point a, Point b)//点a与点b之间的距离 { return sqrt((a-b) * (a-b)); } double getlen(Point a) { return a.x*a.x + a.y*a.y + a.z*a.z; } struct Face { int a, b, c; bool flag; } face; struct CH3D { struct face { int a,b,c;//表示凸包一个面上三个点的编号 bool flag;//表示该面是否属于最终凸包中的面 }; int n; //初始顶点数 Point P[SZ]; //初始顶点 int num; //凸包表面的三角形数 face F[8*SZ];//凸包表面的三角形 int g[SZ][SZ]; Point cross(const Point &a, const Point &b, const Point &c) { return (b-a) ^ (c-a); } double area(Point a,Point b,Point c) //三角形面积*2 { return getlen((b-a) ^ (c-a)); } double volume(Point a,Point b,Point c,Point d) //四面体有向体积*6 { return ((b-a) ^ (c-a)) * (d-a); } double dblcmp(Point &p,face &f) //正:点在面同向 { Point p1 = P[f.b]-P[f.a]; Point p2 = P[f.c]-P[f.a]; Point p3 = p-P[f.a]; return (p1 ^ p2) * p3; } void deal(int p,int a,int b) { int f = g[a][b]; face add; if(F[f].flag) { if(dblcmp(P[p], F[f]) > eps) dfs(p, f); else { add.a = b; add.b = a; add.c = p; add.flag = 1; g[p][b] = g[a][p] = g[b][a] = num; F[num++] = add; } } } void dfs(int p,int now) //递归搜索所有应该从凸包内删除的面 { F[now].flag = false; deal(p,F[now].b,F[now].a); deal(p,F[now].c,F[now].b); deal(p,F[now].a,F[now].c); } bool same(int s,int t) { Point &a = P[F[s].a]; Point &b = P[F[s].b]; Point &c = P[F[s].c]; return fabs(volume(a,b,c,P[F[t].a])) < eps && fabs(volume(a,b,c,P[F[t].b])) < eps && fabs(volume(a,b,c,P[F[t].c])) < eps; } void create() //构建三维凸包 { int i, j, tmp; face add; bool flag = true; num = 0; if(n < 4) return; for(i = 1; i < n; i++) //此段是为了保证前四个点不共面 { if(getlen(P[0] - P[i]) > eps) { swap(P[1], P[i]); flag = false; break; } } if(flag) return; flag = true; for(i = 2; i < n; i++) //使前三点不共线 { if(getlen((P[0]-P[1]) ^ (P[1]-P[i])) > eps) { swap(P[2], P[i]); flag = false; break; } } if(flag) return; flag = true; for(i = 3; i < n; i++) //使前四点不共面 { if(fabs(((P[1]-P[0]) ^ (P[2]-P[0])) * (P[i]-P[0])) > eps) { swap(P[3], P[i]); flag = false; break; } } if(flag) return; for(i = 0; i < 4; i++) { add.a = (i+1)%4; add.b = (i+2)%4; add.c = (i+3)%4; add.flag = true; if(dblcmp(P[i],add) > 0) swap(add.b, add.c); g[add.a][add.b] = g[add.b][add.c] = g[add.c][add.a] = num; F[num++] = add; } for(i = 4; i < n; i++) { for(j = 0; j < num; j++) { if(F[j].flag && dblcmp(P[i],F[j]) > eps) { dfs(i,j); break; } } } tmp = num; for(i = num = 0; i<tmp; i++) if(F[i].flag) { F[num++] = F[i]; } } double area() //表面积 { double res = 0.0; if(n == 3) { Point p = cross(P[0],P[1],P[2]); res = getlen(p) / 2.0; return res; } for(int i = 0; i < num; i++) res += area(P[F[i].a],P[F[i].b],P[F[i].c]); return res/2.0; } double volume() //体积 { double res = 0.0; Point tmp(0,0,0); for(int i = 0; i<num; i++) res += volume(tmp,P[F[i].a],P[F[i].b],P[F[i].c]); return fabs(res/6.0); } int triangle() //表面三角形个数 { return num; } int polygon() //表面多边形个数 { int i,j,res = 0,flag; for(i = 0; i < num; i++) { flag = 1; for(j = 0; j < i; j++) if(same(i,j)) { flag = 0; break; } res += flag; } return res; } Point getcenter()//求凸包质心 { Point ans(0,0,0),temp = P[F[0].a]; double v = 0.0,t2; for(int i = 0; i < num; i++) { if(F[i].flag == true) { Point p1 = P[F[i].a],p2 = P[F[i].b],p3 = P[F[i].c]; t2 = volume(temp,p1,p2,p3)/6.0;//体积大于0,也就是说,点 temp 不在这个面上 if(t2 > 0) { ans.x += (p1.x+p2.x+p3.x+temp.x)*t2; ans.y += (p1.y+p2.y+p3.y+temp.y)*t2; ans.z += (p1.z+p2.z+p3.z+temp.z)*t2; v += t2; } } } ans.x /= (4*v); ans.y /= (4*v); ans.z /= (4*v); return ans; } double function(Point pp) //点到凸包上的最近距离(枚举每个面到这个点的距离) { double min = INF; for(int i = 0; i<num; i++) { if(F[i].flag == true) { Point p1 = P[F[i].a] , p2 = P[F[i].b] , p3 = P[F[i].c]; double a = ( (p2.y-p1.y)*(p3.z-p1.z)-(p2.z-p1.z)*(p3.y-p1.y) ); double b = ( (p2.z-p1.z)*(p3.x-p1.x)-(p2.x-p1.x)*(p3.z-p1.z) ); double c = ( (p2.x-p1.x)*(p3.y-p1.y)-(p2.y-p1.y)*(p3.x-p1.x) ); double d = ( 0-(a*p1.x+b*p1.y+c*p1.z) ); double temp = fabs(a*pp.x+b*pp.y+c*pp.z+d)/sqrt(a*a+b*b+c*c); if(temp < min)min = temp; } } return min; } }; CH3D hull; int main() { while(~scanf("%d", &hull.n)) { for(int i = 0; i < hull.n; i++) { double x, y, z; scanf("%lf %lf %lf", &x, &y, &z); hull.P[i] = Point(x, y, z); } hull.create(); printf("%d ", hull.polygon()); } return 0; }
·旋转卡壳
求平面内的点之间的最长距离
模板:
bool cmp(Point a, Point b) { double tmp = xmul(p[0], a, b); if(sgn(tmp) > 0 || (sgn(tmp) == 0 && getdis(p[0], a) > getdis(p[0], b))) return true; return false; } int top; void graham() { int k = 0; top = 0; for(int i = 1; i < n; i++) if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i; swap(p[0], p[k]); sort(p+1, p+n, cmp); s[top++] = p[0]; s[top++] = p[1]; for(int i = 2;i < n;i ++) { while(top > 1 && xmul(s[top-2], s[top-1], p[i]) < 0) top --; s[top++] = p[i]; } } int RC() { s[top] = s[0]; int now = 1, ans = 0; for(int i = 0; i < top; i++) { while(xmul(s[i], s[i+1], s[now]) < xmul(s[i], s[i+1], s[now+1])) { now++; if(now == top) now = 0; } ans = max(ans, max(getdis(s[now], s[i]), getdis(s[now], s[i+1]))); } return ans; }
·半平面交
/*半平面相交(直线切割多边形)(点标号从1开始)*/ Point points[MAXN],p[MAXN],q[MAXN]; int n; double r; int cCnt,curCnt; inline void getline(Point x,Point y,double &a,double &b,double &c){ a = y.y - x.y; b = x.x - y.x; c = y.x * x.y - x.x * y.y; } inline void initial(){ for(int i = 1; i <= n; ++i)p[i] = points[i]; p[n+1] = p[1]; p[0] = p[n]; cCnt = n; } inline Point intersect(Point x,Point y,double a,double b,double c){ double u = fabs(a * x.x + b * x.y + c); double v = fabs(a * y.x + b * y.y + c); return Point( (x.x * v + y.x * u) / (u + v) , (x.y * v + y.y * u) / (u + v) ); } inline void cut(double a,double b ,double c){ curCnt = 0; for(int i = 1; i <= cCnt; ++i){ if(a*p[i].x + b*p[i].y + c >= EPS)q[++curCnt] = p[i]; else { if(a*p[i-1].x + b*p[i-1].y + c > EPS){ q[++curCnt] = intersect(p[i],p[i-1],a,b,c); } if(a*p[i+1].x + b*p[i+1].y + c > EPS){ q[++curCnt] = intersect(p[i],p[i+1],a,b,c); } } } for(int i = 1; i <= curCnt; ++i)p[i] = q[i]; p[curCnt+1] = q[1];p[0] = p[curCnt]; cCnt = curCnt; } inline void solve(){ //注意:默认点是顺时针,如果题目不是顺时针,规整化方向 initial(); for(int i = 1; i <= n; ++i){ double a,b,c; getline(points[i],points[i+1],a,b,c); cut(a,b,c); } /* 如果要向内推进r,用该部分代替上个函数 for(int i = 1; i <= n; ++i){ Point ta, tb, tt; tt.x = points[i+1].y - points[i].y; tt.y = points[i].x - points[i+1].x; double k = r / sqrt(tt.x * tt.x + tt.y * tt.y); tt.x = tt.x * k; tt.y = tt.y * k; ta.x = points[i].x + tt.x; ta.y = points[i].y + tt.y; tb.x = points[i+1].x + tt.x; tb.y = points[i+1].y + tt.y; double a,b,c; getline(ta,tb,a,b,c); cut(a,b,c); } */ //多边形核的面积 double area = 0; for(int i = 1; i <= curCnt; ++i) area += p[i].x * p[i + 1].y - p[i + 1].x * p[i].y; area = fabs(area / 2.0); //此时cCnt为最终切割得到的多边形的顶点数,p为存放顶点的数组 } inline void GuiZhengHua(){ //规整化方向,逆时针变顺时针,顺时针变逆时针 for(int i = 1; i < (n+1)/2; i ++) swap(points[i], points[n-i]);//头文件加iostream } inline void init(){ for(int i = 1; i <= n; ++i)points[i].input(); points[n+1] = points[1]; }
裸题:POJ 2187
求n个点之间的最长距离的平方
1 #include <iostream> 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <algorithm> 7 #include <queue> 8 using namespace std; 9 const int SZ = 50200; 10 const int INF = 1e9+10; 11 const double eps = 1e-8; 12 const double pi = acos(-1.0); 13 using namespace std; 14 int sgn(double x) 15 { 16 if(fabs(x) < eps) return 0; 17 if(x < 0) return -1; 18 return 1; 19 } 20 struct Point 21 { 22 double x, y; 23 Point () {} 24 Point (double x, double y) : x(x), y(y) {} 25 Point operator +(const Point &a)const{ 26 return (Point){x + a.x, y + a.y}; 27 } 28 Point operator -(const Point &a)const{ 29 return (Point){x - a.x, y - a.y}; 30 } 31 bool operator ==(const Point &a)const{ 32 if(sgn(x - a.x) == 0 && sgn(y - a.y) == 0) return true; 33 return false; 34 } 35 bool operator !=(const Point &a)const{ 36 return x != a.x || y != a.y; 37 } 38 bool operator <(const Point &a)const{ 39 if(a.x != x) return x < a.x;//以x作为第一关键字排序 40 return y < a.y; 41 } 42 double operator *(const Point &a)const{//点乘 43 return x * a.x + y * a.y; 44 } 45 double operator ^(const Point &a)const{//叉乘 46 return x * a.y - y * a.x; 47 } 48 }p[SZ], s[SZ]; 49 double xmul(Point a, Point b, Point c) //ab * ac, xmul<0表示p0在se左 50 { 51 return (b - a) ^ (c - a); 52 } 53 int getdis(Point a, Point b)//点a与点b之间的距离 54 { 55 return (a-b) * (a-b); 56 } 57 int n; 58 bool cmp(Point a, Point b) 59 { 60 double tmp = xmul(p[0], a, b); 61 if(sgn(tmp) > 0 || (sgn(tmp) == 0 && getdis(p[0], a) > getdis(p[0], b))) return true; 62 return false; 63 } 64 int top; 65 void graham() 66 { 67 int k = 0; 68 top = 0; 69 for(int i = 1; i < n; i++) 70 if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i; 71 swap(p[0], p[k]); 72 sort(p+1, p+n, cmp); 73 s[top++] = p[0]; s[top++] = p[1]; 74 for(int i = 2;i < n;i ++) 75 { 76 while(top > 1 && xmul(s[top-2], s[top-1], p[i]) < 0) 77 top --; 78 s[top++] = p[i]; 79 } 80 } 81 int RC() 82 { 83 s[top] = s[0]; 84 int now = 1, ans = 0; 85 for(int i = 0; i < top; i++) 86 { 87 while(xmul(s[i], s[i+1], s[now]) < xmul(s[i], s[i+1], s[now+1])) 88 { 89 now++; 90 if(now == top) now = 0; 91 } 92 ans = max(ans, max(getdis(s[now], s[i]), getdis(s[now], s[i+1]))); 93 } 94 return ans; 95 } 96 int main() 97 { 98 scanf("%d", &n); 99 for(int i = 0; i < n; i++) 100 { 101 double x, y; 102 scanf("%lf %lf", &x, &y); 103 p[i] = Point(x, y); 104 } 105 graham(); 106 printf("%d ", RC()); 107 return 0; 108 }
·半平面交
模板:
1 /*半平面相交(直线切割多边形)(点标号从1开始)*/ 2 Point points[SZ],p[SZ],q[SZ]; 3 int n; 4 double r; 5 int cCnt,curCnt; 6 inline void getline(Point x,Point y,double &a,double &b,double &c) 7 { 8 a = y.y - x.y; 9 b = x.x - y.x; 10 c = y.x * x.y - x.x * y.y; 11 } 12 inline void initial() 13 { 14 for(int i = 1; i <= n; ++i) p[i] = points[i]; 15 p[n+1] = p[1]; 16 p[0] = p[n]; 17 cCnt = n; 18 } 19 inline Point intersect(Point x,Point y,double a,double b,double c) 20 { 21 double u = fabs(a * x.x + b * x.y + c); 22 double v = fabs(a * y.x + b * y.y + c); 23 return Point( (x.x * v + y.x * u) / (u + v) , (x.y * v + y.y * u) / (u + v) ); 24 } 25 inline void cut(double a,double b ,double c) 26 { 27 curCnt = 0; 28 for(int i = 1; i <= cCnt; ++i) 29 { 30 if(a*p[i].x + b*p[i].y + c >= eps)q[++curCnt] = p[i]; 31 else 32 { 33 if(a*p[i-1].x + b*p[i-1].y + c > eps) 34 { 35 q[++curCnt] = intersect(p[i],p[i-1],a,b,c); 36 } 37 if(a*p[i+1].x + b*p[i+1].y + c > eps) 38 { 39 q[++curCnt] = intersect(p[i],p[i+1],a,b,c); 40 } 41 } 42 } 43 for(int i = 1; i <= curCnt; ++i)p[i] = q[i]; 44 p[curCnt+1] = q[1]; 45 p[0] = p[curCnt]; 46 cCnt = curCnt; 47 } 48 inline void solve() 49 { 50 //注意:默认点是顺时针,如果题目不是顺时针,规整化方向 51 initial(); 52 for(int i = 1; i <= n; ++i) 53 { 54 double a,b,c; 55 getline(points[i],points[i+1],a,b,c); 56 cut(a,b,c); 57 } 58 /* 59 如果要向内推进r,用该部分代替上个函数 60 for(int i = 1; i <= n; ++i){ 61 Point ta, tb, tt; 62 tt.x = points[i+1].y - points[i].y; 63 tt.y = points[i].x - points[i+1].x; 64 double k = r / sqrt(tt.x * tt.x + tt.y * tt.y); 65 tt.x = tt.x * k; 66 tt.y = tt.y * k; 67 ta.x = points[i].x + tt.x; 68 ta.y = points[i].y + tt.y; 69 tb.x = points[i+1].x + tt.x; 70 tb.y = points[i+1].y + tt.y; 71 double a,b,c; 72 getline(ta,tb,a,b,c); 73 cut(a,b,c); 74 } 75 */ 76 //多边形核的面积 77 double area = 0; 78 for(int i = 1; i <= curCnt; ++i) 79 area += p[i].x * p[i + 1].y - p[i + 1].x * p[i].y; 80 area = fabs(area / 2.0); 81 //此时cCnt为最终切割得到的多边形的顶点数,p为存放顶点的数组 82 } 83 inline void GuiZhengHua() 84 { 85 //规整化方向,逆时针变顺时针,顺时针变逆时针 86 for(int i = 1; i < (n+1)/2; i ++) 87 swap(points[i], points[n-i]);//头文件加iostream 88 } 89 inline void init() 90 { 91 scanf("%d", &n); 92 for(int i = 1; i <= n; ++i) 93 { 94 double x, y; 95 scanf("%lf %lf", &x, &y); 96 points[i] = Point(x, y); 97 } 98 points[n+1] = points[1]; 99 }
·圆交多边形
模板:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <queue> using namespace std; const int SZ = 520; const int INF = 1e9+10; const double eps = 1e-8; const double pi = acos(-1.0); int n; int sgn(double x) { if(fabs(x) < eps) return 0; if(x < 0) return -1; return 1; } struct Point { double x, y; Point () {} Point (double x, double y) : x(x), y(y) {} Point operator +(const Point &a)const{ return Point(x + a.x, y + a.y); } Point operator -(const Point &a)const{ return Point(x - a.x, y - a.y); } bool operator ==(const Point &a)const{ if(sgn(x - a.x) == 0 && sgn(y - a.y) == 0) return true; return false; } bool operator !=(const Point &a)const{ return x != a.x || y != a.y; } bool operator <(const Point &a)const{ if(a.x != x) return x < a.x;//以x作为第一关键字排序 return y < a.y; } double operator *(const Point &a)const{//点乘 return x * a.x + y * a.y; } double operator ^(const Point &a)const{//叉乘 return x * a.y - y * a.x; } double sqrx() //向量的模 { return sqrt(x*x+y*y); } }p[SZ], A, B; double xmult(Point a, Point b, Point c) //ab * ac, xmul<0表示p0在se左 { return (b - a) ^ (c - a); } double getsqrtdis(Point a, Point b)//点a与点b之间的距离 { return sqrt((a-b) * (a-b)); } double getdis(Point a, Point b) { return (a-b) * (a-b); } Point crossline(Point u1, Point v1, Point u2, Point v2)//直线u1v1与直线u2v2的交点 { double a1 = (v2 - u2) ^ (u1 - u2); double a2 = (v2 - u2) ^ (v1 - u2); return Point( (u1.x*a2 - v1.x*a1) / (a2 - a1), (u1.y*a2 - v1.y*a1) / (a2 - a1) ); } void intersection_line_circle(Point c,double r,Point l1,Point l2,Point& p1,Point& p2){ Point p=c; double t; p.x+=l1.y-l2.y; p.y+=l2.x-l1.x; p=crossline(p,c,l1,l2); t=sqrt(r*r-getsqrtdis(p,c)*getsqrtdis(p,c))/getsqrtdis(l1,l2); p1.x=p.x+(l2.x-l1.x)*t; p1.y=p.y+(l2.y-l1.y)*t; p2.x=p.x-(l2.x-l1.x)*t; p2.y=p.y-(l2.y-l1.y)*t; } Point ptoseg(Point p,Point l1,Point l2) //点到线段的最近距离 { Point t=p; t.x+=l1.y-l2.y,t.y+=l2.x-l1.x; if (xmult(l1,t,p)*xmult(l2,t,p)>eps) return getsqrtdis(p,l1)<getsqrtdis(p,l2)?l1:l2; return crossline(p,t,l1,l2); } struct Circle { Point c; double r; Circle() {} Circle(Point c, double r) : c(c), r(r) {} }C; double Triangle_Circle_Area(Point a,Point b,Point o,double r) { double sign=1.0; a=a-o; b=b-o; o=Point(0.0,0.0); if(fabs(xmult(a,b,o))<eps) return 0.0; if(getdis(a,o)>getdis(b,o)) { swap(a,b); sign=-1.0; } if(getdis(a,o)<r*r+eps) { if(getdis(b,o)<r*r+eps) return xmult(a,b,o)/2.0*sign; Point p1,p2; intersection_line_circle(o,r,a,b,p1,p2); if(getsqrtdis(p1,b)>getsqrtdis(p2,b)) swap(p1,p2); double ret1=fabs(xmult(a,p1,o)); double ret2=acos( p1*b/p1.sqrx()/b.sqrx() )*r*r; double ret=(ret1+ret2)/2.0; if(xmult(a,b,o)<eps && sign>0.0 || xmult(a,b,o)>eps && sign<0.0) ret=-ret; return ret; } Point ins=ptoseg(o,a,b); if(getdis(o,ins)>r*r-eps) { double ret=acos( a*b/a.sqrx()/b.sqrx() )*r*r/2.0; if(xmult(a,b,o)<eps && sign>0.0 || xmult(a,b,o)>eps && sign<0.0) ret=-ret; return ret; } Point p1,p2; intersection_line_circle(o,r,a,b,p1,p2); double cm=r/(getsqrtdis(o,a)-r); Point m=Point( (o.x+cm*a.x)/(1+cm) , (o.y+cm*a.y)/(1+cm) ); double cn=r/(getsqrtdis(o,b)-r); Point n=Point( (o.x+cn*b.x)/(1+cn) , (o.y+cn*b.y)/(1+cn) ); double ret1 = acos( m*n/m.sqrx()/n.sqrx() )*r*r; double ret2 = acos( p1*p2/p1.sqrx()/p2.sqrx() )*r*r-fabs(xmult(p1,p2,o)); double ret=(ret1-ret2)/2.0; if(xmult(a,b,o)<eps && sign>0.0 || xmult(a,b,o)>eps && sign<0.0) ret=-ret; return ret; } int main() { double k; int tt = 0; while(~scanf("%d %lf", &n, &k)) { double x, y; for(int i = 1; i <= n; i++) { scanf("%lf %lf", &x, &y); p[i] = Point(x, y); } scanf("%lf %lf", &x, &y); A = Point(x, y); scanf("%lf %lf", &x, &y); B = Point(x, y); double D = (2*k*k*A.x - 2*B.x) / (1 - k*k); double E = (2*k*k*A.y - 2*B.y) / (1 - k*k); double F = (B.x*B.x + B.y*B.y - k*k*A.x*A.x - k*k*A.y*A.y) / (1 - k*k); C = Circle(Point(-D/2, -E/2), sqrt(D*D/4 + E*E/4 - F) ); double ans = 0.0; p[n+1] = p[1]; for(int i = 1; i <= n; i++) ans += Triangle_Circle_Area(p[i], p[i+1], C.c, C.r); printf("Case %d: %.10f ", ++tt, fabs(ans)); } return 0; }