专题基本全都是模版应用。贴一下模版
平面最近点对
const double INF = 1e16; const int MAXN = 200010; struct Point { int x,y; int type; }; double dist(Point a,Point b) { return sqrt(1.0 * (a.x - b.x) * (a.x - b.x) + 1.0 * (a.y - b.y) * (a.y - b.y)); } Point p[MAXN]; int n,s[MAXN]; int cmpx(int i,int j) {return p[i].x - p[j].x < 0;} int cmpy(int i,int j) {return p[i].y - p[j].y < 0;} double closet_pair(int * s,int l,int r) { double ans = INF; if (r - l < 20) { for (int q = l ; q < r ; q++) for (int w = q + 1 ; w < r ; w++) if ((p[s[q]].type ^ p[s[w]].type) == 1) ans = min(ans,dist(p[s[q]],p[s[w]])); return ans; } int lft,rht,mid = (l + r) / 2; ans = min(closet_pair(s,l,mid),closet_pair(s,mid,r)); for (lft = l ; p[s[lft]].x < p[s[mid]].x - ans; lft++); for (rht = r - 1 ; p[s[rht]].x > p[s[mid]].x + ans ; rht--); sort(s + lft,s + rht,cmpy); for (int q = lft ; q < rht ; q++) { for (int w = q + 1 ; w < min(rht,q + 6) ; w++) { if ((p[s[q]].type ^ p[s[w]].type) == 1) { ans = min(ans,dist(p[s[q]],p[s[w]])); } } } sort(s + lft,s + rht,cmpx); return ans; } int main() { int N; scanf("%d",&N); for (int i = 0 ; i < N ; i++) { scanf("%d%d",&p[i].x,&p[i].y); p[i].type = 0; } for (int i = N ; i < N + N ; i++) { scanf("%d%d",&p[i].x,&p[i].y); p[i].type = 1; } for (int i = 0 ; i < N + N ; i++) s[i] = i; sort(s,s + N + N,cmpx); printf("%.3lf\n",closet_pair(s,0,2 * N)); }
const double eps = 1e-8; const int INF = 0x3f3f3f3f; 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 tx,double ty) { x = tx; y = ty; } Point operator - (const Point &b) const { return Point(x - b.x,y - b.y); } //叉积 double operator ^ (const Point &b) const { return x * b.y - y * b.x; } //点积 double operator * (const Point &b) const { return x * b.x + y * b.y; } //绕源点旋转B(弧度)。后X,Y变化 void transxy(double B) // { double tx = x; double ty = y; x = tx * cos(B) - ty * sin(B); y = ty * sin(B) + tx * cos(B); } }; struct Line { Point s,e; Line(){} Line(Point a,Point b) { s = a; e = b; } //两直线求交点。这个可以用来求线段交点。 // 首先判断线段相交然后可以直接利用这个判线段交点 //first为0表示重合,1表示平行,2表示相交 pair<int,Point> operator & (const Line &b) const { Point res = s; if (sgn((s - e) ^ (b.s - b.e)) == 0) { if (sgn((s - b.e) ^ (b.s - b.e)) == 0) return make_pair(0,res);//重合 else return make_pair(1,res);//平行 } double t = ((s - b.s) ^ (b.s - b.e)) / ((s - e) ^ (b.s - b.e));//相交 res.x += (e.x - s.x) * t; res.y += (e.y - s.y) * t; return make_pair(2,res); } }; double dist(Point a,Point b) { return sqrt((b - a) * (b - a)); } //判断线段是否相交 bool inter(Line l1,Line l2) { return 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) && 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) && sgn((l2.s - l1.s) ^ (l1.e - l1.s)) * sgn((l2.e - l1.s) ^ (l1.e - l1.s)) <= 0 && sgn((l1.s - l2.s) ^ (l2.e - l1.s)) * sgn((l1.e - l2.s) ^ (l2.e - l2.s)) <= 0; }
bool OnSeg(Point P,Line L) { return sgn((L.s-P)^(L.e-P)) == 0 && sgn((P.x - L.s.x) * (P.x - L.e.x)) <= 0 && sgn((P.y - L.s.y) * (P.y - L.e.y)) <= 0; } //判断点在凸多边形内 //点形成一个凸包,而且按逆时针排序(如果是顺时针把里面的<0改为>0)一定注意时针顺序否则会WA //点的编号:0~n-1 //返回值: //-1:点在凸多边形外 //0:点在凸多边形边界上 //1:点在凸多边形内 int inConvexPoly(Point a,Point p[],int n) { for(int i = 0 ; i < n ; i++) { if(sgn((p[i] - a) ^ (p[(i + 1) % n] - a)) < 0)return -1; else if(OnSeg(a,Line(p[i],p[(i + 1) % n])))return 0; } return 1; } //判断点在任意多边形内 //射线法,poly[]的顶点数要大于等于3,点的编号0~n-1 //返回值 //-1:点在凸多边形外 //0:点在凸多边形边界上 //1:点在凸多边形内 int inPoly(Point p,Point poly[],int n) { int cnt; Line ray,side; cnt = 0; ray.s = p; ray.e.y = p.y; ray.e.x = -100000000000.0;//-INF,注意取值防止越界 for(int i = 0;i < n;i++) { side.s = poly[i]; side.e = poly[(i+1)%n]; if(OnSeg(p,side))return 0; //如果平行轴则不考虑 if(sgn(side.s.y - side.e.y) == 0) continue; if(OnSeg(side.s,ray)) { if(sgn(side.s.y - side.e.y) > 0)cnt++; } else if(OnSeg(side.e,ray)) { if(sgn(side.e.y - side.s.y) > 0)cnt++; } else if(inter(ray,side)) cnt++; } if(cnt % 2 == 1)return 1; else return -1; }
//判断凸多边形 //允许共线边 //点可以是顺时针给出也可以是逆时针给出 //点的编号1~n-1 bool isconvex(Point poly[],int n) { bool s[3]; memset(s,false,sizeof(s)); for(int i = 0;i < n;i++) { s[sgn( (poly[(i + 1) % n]-poly[i]) ^ (poly[(i + 2) % n] - poly[i]) ) + 1] = true; if(s[0] && s[2])return false; } return true; } //点到线段的距离 //返回点到线段最近的点 Point NearestPointToLineSeg(Point P,Line L) { Point result; double t = ((P - L.s)*(L.e - L.s)) / ((L.e - L.s)*(L.e - L.s)); if(t >= 0 && t <= 1) { result.x = L.s.x + (L.e.x - L.s.x) * t; result.y = L.s.y + (L.e.y - L.s.y) * t; } else { if(dist(P,L.s) < dist(P,L.e)) result = L.s; else result = L.e; } return result; } //*判断点在线段上 bool OnSeg(Point P,Line L) { return sgn((L.s-P)^(L.e-P)) == 0 && sgn((P.x - L.s.x) * (P.x - L.e.x)) <= 0 && sgn((P.y - L.s.y) * (P.y - L.e.y)) <= 0; } //*判断点在凸多边形内 //点形成一个凸包,而且按逆时针排序(如果是顺时针把里面的<0改为>0) //点的编号:0~n-1 //返回值: //-1:点在凸多边形外 //0:点在凸多边形边界上 //1:点在凸多边形内 int inConvexPoly(Point a,Point p[],int n) { for(int i = 0 ; i < n ; i++) { if(sgn((p[i] - a) ^ (p[(i + 1) % n] - a)) < 0)return -1; else if(OnSeg(a,Line(p[i],p[(i + 1) % n])))return 0; } return 1; } bool inter(Line l1,Line l2) { return 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) && 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) && sgn((l2.s - l1.e) ^ (l1.s - l1.e)) * sgn((l2.e - l1.e) ^ (l1.s - l1.e)) <= 0 && sgn((l1.s - l2.e) ^ (l2.s - l2.e)) * sgn((l1.e - l2.e) ^ (l2.s - l2.e)) <= 0; } //*判断点在任意多边形内 //射线法,poly[]的顶点数要大于等于3,点的编号0~n-1 //返回值 //-1:点在凸多边形外 //0:点在凸多边形边界上 //1:点在凸多边形内 int inPoly(Point p,Point poly[],int n) { int cnt; Line ray,side; cnt = 0; ray.s = p; ray.e.y = p.y; ray.e.x = -100000000000.0;//-INF,注意取值防止越界 for(int i = 0;i < n;i++) { side.s = poly[i]; side.e = poly[(i+1)%n]; if(OnSeg(p,side))return 0; //如果平行轴则不考虑 if(sgn(side.s.y - side.e.y) == 0) continue; if(OnSeg(side.s,ray)) { if(sgn(side.s.y - side.e.y) > 0)cnt++; } else if(OnSeg(side.e,ray)) { if(sgn(side.e.y - side.s.y) > 0)cnt++; } else if(inter(ray,side)) cnt++; } if(cnt % 2 == 1)return 1; else return -1; }
计算有向面积
double CalcArea(Point * p,int n) {
double res = 0;
for (int i = 0 ; i < n ; i++)
res += (p[i] ^ p[(i + 1) % n]);
return fabs(res);
}
POJ 2318 TOYS
给出区域,要你算出给出的每个点在第几个区域里
利用叉积的方向性二分判断在第几个区域内
#include <map> #include <set> #include <list> #include <cmath> #include <ctime> #include <deque> #include <stack> #include <queue> #include <cctype> #include <cstdio> #include <string> #include <vector> #include <climits> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define LL long long #define PI 3.1415926535897932626 typedef long long type; using namespace std; type gcd(type a, type b) {return b == 0 ? a : gcd(b, a % b);} const int MAXN = 5030; struct Point { int x,y; Point(){} Point(int _x,int _y) { x = _x;y = _y; } Point operator - (const Point &b)const { return Point(x - b.x,y - b.y); } int operator * (const Point &b)const { return x*b.x + y*b.y; } int operator ^ (const Point &b)const { return x*b.y - y*b.x; } }; struct Line { Point s,e; Line(){} Line(Point _s,Point _e) { s = _s;e = _e; } }; int xmult(Point p0,Point p1,Point p2) //计算p0p1 X p0p2 { return (p1 - p0) ^ (p2 - p0); } Line line[MAXN]; int ret[MAXN]; int N,M; double X1,Y1,X2,Y2; int main() { bool first = true; while (scanf("%d",&N) != EOF) { if(N == 0) break; if (first) first = false; else putchar('\n'); memset(ret,0,sizeof(ret)); scanf("%d%lf%lf%lf%lf",&M,&X1,&Y1,&X2,&Y2); int UI,LI; for (int i = 0 ; i < N ; i++) { scanf("%d%d",&UI,&LI); line[i] = Line(Point(UI,Y1),Point(LI,Y2)); } line[N] = Line(Point(X2,Y1),Point(X2,Y2)); Point p; memset(ret,0,sizeof(ret)); while (M--) { int x,y; scanf("%d%d",&x,&y); p = Point(x,y); int l = 0,r = N; int ans; while (l <= r) { int mid = (l + r) / 2; if (xmult(p,line[mid].s,line[mid].e) < 0) { ans = mid; r = mid - 1; } else l = mid + 1; } ret[ans]++; } for (int i = 0 ; i <= N ; i++) printf("%d: %d\n",i,ret[i]); } return 0; }