专题基本全都是模版应用。贴一下模版

 

平面最近点对

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;
}
View Code

相关文章: