Kuangbin 带你飞-基础计算几何专题 题解

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

 

平面最近点对

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

POJ 2398 Toy Storage

跟上面的那个题一样的只是改变了一下答案的方式

#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;
int num[MAXN];
double X1,Y1,X2,Y2;
const int cmp(Line a,Line b)
{
    return a.s.x < b.s.x;
}

int main()
{
    bool first = true;
    while (scanf("%d",&N) != EOF)
    {
        if(N == 0) break;
        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;
        sort(line ,line + N + 1,cmp);
        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 = 1 ; i <= N ; i++)num[i] = 0;
        for (int i = 0 ; i <= N ; i++)
            if (ret[i] > 0) num[ret[i]]++;
        puts("Box");
        for (int i = 1 ; i <= N ; i++)
            if (num[i] > 0) printf("%d: %d\n",i,num[i]);
    }
    return 0;
}
View Code

POJ 3304 segments

如果存在这样的直线满足条件,那么可以做这条直线的垂线,那么这条垂线就会

与所有线段相交于是问题转换为询问是否存在一条直线与所有线段相交

#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
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 110;
const double eps = 1e-8;
/*如果有存在这样的直线,过投影相交区域作直线的垂线,
该垂线必定与每条线段相交,
问题转化为问是否存在一条线和所有线段相交
*/
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;
    }
};

struct Line
{
    Point s,e;
    Line(){}
    Line(Point a,Point b)
    {
        s = a;
        e = b;
    }
};

double xmult(Point p0,Point p1,Point p2)//P0P1 ^ POP2;
{
    return (p1 - p0) ^ (p2 - p0);
}

bool seg_inter_line(Line l1,Line l2)//line l1,seg l2
{
    return sgn(xmult(l2.s,l1.s,l1.e)) * sgn(xmult(l2.e,l1.s,l1.e)) <= 0;
}

double dist(Point a,Point b)
{
    return sqrt((b - a) * (b - a));
}

Line line[MAXN];
bool judge(Line l1,int n)
{
    if (sgn(dist(l1.s,l1.e)) == 0) return false;
    for (int i = 0 ; i < n ; i++)
    {
        if (seg_inter_line(l1,line[i]) == false) return false;
    }
    return true;
}

int main()
{
    int T,n;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d",&n);
        double x1,y1,x2,y2;
        for (int i = 0 ; i < n ; i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            line[i] = Line(Point(x1,y1) ,Point(x2,y2));
        }
        bool flag = false;
        for (int i = 0 ; i < n && !flag ; i++)
            for (int j = 0 ; j < n && !flag ; j++)
        {
            if (judge(Line(line[i].s,line[j].s),n) ||
                judge(Line(line[i].s,line[j].e),n) ||
                judge(Line(line[i].e,line[j].s),n) ||
                judge(Line(line[i].e,line[j].e),n))
            flag = true;
        }
        if (flag) puts("Yes!");
        else puts("No!");
    }
    return false;
}
View Code

POJ 1269 Intersecting Lines

直接判断直线相交的情况

#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
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const double eps = 1e-8;

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

struct Line
{
    Point s,e;
    Line(){}
    Line(Point a,Point b)
    {
        s = a;
        e = b;
    }

    pair<Point,int> operator & (const Line b) const
    {
        Point res = s;
        if (sgn((s - e) ^ (b.s - b.e)) == 0)
        {
            if (sgn((b.s - s) ^ (b.e - s)) == 0)
                return make_pair(res,0);//same
            else return make_pair(res,1);//parell
        }
        double tmp = ((s - b.s) ^ (b.s - b.e)) / ((s - e) ^ (b.s - b.e));
        res.x += (e.x - s.x) * tmp;
        res.y += (e.y - s.y) * tmp;
        return make_pair(res,2);
    }
};

int main()
{
    int T;
    scanf("%d",&T);
    printf("INTERSECTING LINES OUTPUT\n");
    while (T--)
    {
        double x1,y1,x2,y2,x3,y3,x4,y4;
        scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&x1,&y1,&x2,&y2,&x3,&y3,&x4,&y4);
        Line line1 = Line(Point(x1,y1),Point(x2,y2));
        Line line2 = Line(Point(x3,y3),Point(x4,y4));
        pair<Point,int> ans = line1 & line2;
        if (ans.second == 2) printf("POINT %.2f %.2f\n",ans.first.x,ans.first.y);
        else if (ans.second == 1) puts("NONE");
        else puts("LINE");
    }
    puts("END OF OUTPUT");
    return 0;
}
View Code

POJ 1556 the doors

注意如果线段相交交点是端点的话扔钱可以继续传递

所以题目总有一段特判

#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
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const double eps = 1e-8;
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;
    }
};

struct Line
{
    Point s,e;
    Line(){}
    Line(Point a,Point b)
    {
        s = a;
        e = b;
    }
};

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 - l2.s)) * sgn((l1.e - l2.s) ^ (l2.e - l2.s)) <= 0;
}

double dist(Point a,Point b)
{
    return sqrt((b - a) * (b - a));
}

const int MAXN = 200;
Line line[MAXN];
double dis[MAXN][MAXN];
const double INF = 1e15;
Point point[MAXN * 2];
int cas,tot;

bool judge(Line cur)
{
    for (int i = 1 ; i <= cas ; i++)
        if (line[i].s.x == cur.s.x || line[i].s.x == cur.e.x) continue;
        else if (inter(cur,line[i])) return false;
    return true;
}

int main()
{
   // freopen("sample.txt","r",stdin);
    int N;
    while (scanf("%d",&N) != EOF)
    {
        if (N == -1) break;
        double x,y1,y2,y3,y4;
        cas = 0;
        tot = 0;
        for (int i = 1 ; i <= N ; i++)
        {
            scanf("%lf%lf%lf%lf%lf",&x,&y1,&y2,&y3,&y4);
            line[++cas] = Line(Point(x,0),Point(x,y1));
            line[++cas] = Line(Point(x,y2),Point(x,y3));
            line[++cas] = Line(Point(x,y4),Point(x,10));
            point[++tot] = Point(x,y1);
            point[++tot] = Point(x,y2);
            point[++tot] = Point(x,y3);
            point[++tot] = Point(x,y4);
        }
        for (int i = 0 ; i < MAXN ; i++)
            for (int j = 0 ; j < MAXN ; j++)
                dis[i][j] = i == j ? 0 : INF;
        for (int i = 1 ; i <= tot ; i++)
        {
            Line tmp = Line(point[i],Point(0,5.0));
            if (judge(tmp)) dis[0][i] = dist(point[i],Point(0,5.0));
        }
       // for (int i = 1 ; i <= tot ; i++)
         //   printf("%.2lf %.2lf %.2lf\n",point[i].x,point[i].y,dis[0][i]);
        for (int i = 1 ; i <= tot ; i++)
        {
            for (int j = 1 ; j <= tot ; j++)
            {
                if (i == j) continue;
                Line tmp = Line(point[i],point[j]);
                if (judge(tmp)) dis[i][j] = dist(point[i],point[j]);
            }
        }
        for (int i = 1 ; i <= tot ; i++)
        {
            Line tmp = Line(point[i],Point(10,5));
            if (judge(tmp)) dis[i][tot + 1] = dist(point[i],Point(10,5));
        }
        Line tmp = Line(Point(0,5),Point(10,5));
        if (judge(tmp)) dis[0][tot + 1] = 10;
        for (int k = 0 ;  k <= tot + 1 ; k++)
        {
            for (int i = 0 ; i <= tot +  1 ; i++)
                for (int j = 0 ; j <= tot + 1 ; j++)
                    dis[i][j] = min(dis[i][j],dis[i][k] + dis[k][j]);
        }
        printf("%.2f\n",dis[0][tot + 1]);
    }
    return 0;
}
View Code

POJ 2653 Pick up Sticks

暴力枚举判断线段相交

#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
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const double eps = 1e-8;
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;
    }
};

struct Line
{
    Point s,e;
    Line(){}
    Line(Point a,Point b)
    {
        s = a;
        e = b;
    }
};

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 - l2.s)) * sgn((l1.e - l2.s) ^ (l2.e - l2.s)) <= 0;
}

const int MAXN = 100010;
Line line[MAXN];
bool flag[MAXN];

int main()
{
    int N;
    while (scanf("%d",&N) != EOF)
    {
        if (N == 0) break;
        memset(flag,false,sizeof(flag));
        for (int i = 1 ; i <= N ; i++)
        {
            double x1,y1,x2,y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            line[i] = Line(Point(x1,y1),Point(x2,y2));
        }
        for (int i = 1 ; i <= N ; i++)
        {
            for (int j = i + 1 ; j <= N ; j++)
            {
                if (inter(line[i],line[j]))
                {
                    flag[i] = true;
                    break;
                }
            }
        }
        printf("Top sticks: ");
        bool first = true;
        for (int i = 1 ; i <= N ; i++)
        {
            if (!flag[i])
            {
                if (first) first = false;
                else printf(", ");
                printf("%d",i);
            }
        }
        puts(".");
    }
    return 0;
}
View Code

POJ 1066 Treasure Hunt

#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
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
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;
    }

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

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

const int MAXN = 110;
Line line[MAXN];
Point s;
Point p[MAXN];
int cas;

int main()
{
    int n;
    while (scanf("%d",&n) != EOF)
    {
        cas = 0;
        double x1,y1,x2,y2;
        for (int i = 1 ; i <= n ; i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            line[i] = Line(Point(x1,y1),Point(x2,y2));
            p[++cas] = Point(x1,y1);
            p[++cas] = Point(x2,y2);
        }
        scanf("%lf%lf",&x1,&y1);
        s = Point(x1,y1);;
        int ans = INF;
        for (int i = 1 ; i <= cas;  i++)
        {
            int cnt = 0;
            Line tmp = Line(s,p[i]);
            for (int j = 1 ; j <= n ; j++)
                if (inter(tmp,line[j])) cnt++;
            ans = min(ans,cnt);
        }
        Line tmp;
        tmp = Line(s,Point(0,0));
        int cnt = 0;
        for (int j = 1 ; j <= n ; j++)
            if (inter(tmp,line[j])) cnt++;
        ans = min(ans,cnt + 1);

        tmp = Line(s,Point(0,100));
        cnt = 0;
        for (int j = 1 ; j <= n ; j++)
            if (inter(tmp,line[j])) cnt++;
        ans = min(ans,cnt + 1);

        tmp = Line(s,Point(100,0));
        cnt = 0;
        for (int j = 1 ; j <= n ; j++)
            if (inter(tmp,line[j])) cnt++;
        ans = min(ans,cnt + 1);

        tmp = Line(s,Point(100,100));
        cnt = 0;
        for (int j = 1 ; j <= n ; j++)
            if (inter(tmp,line[j])) cnt++;
        ans = min(ans,cnt + 1);
        printf("Number of doors = %d\n",ans);
    }
    return 0;
}
View Code

POJ 1410 Intersection

#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
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const double eps = 1e-6;
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;
    }

    void transxy(double B)
    {
        double tx = x;
        double ty = y;
        x = tx * cos(B) - ty * sin(B);
        y = tx * sin(B) + ty * cos(B);
    }
};

struct Line
{
    Point s,e;
    Line(){}
    Line(Point a,Point b)
    {
        s = a;
        e = b;
    }

    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);
    }
};

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)
//点的编号: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;
}


int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        double x1,y1,x2,y2;
        scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
        Line line = Line(Point(x1,y1),Point(x2,y2));
        scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
        if (x1 > x2) swap(x1,x2);
        if (y1 > y2) swap(y1,y2);
        Point tmp[10];
        tmp[0] = Point(x1,y1);
        tmp[1] = Point(x2,y1);
        tmp[2] = Point(x2,y2);
        tmp[3] = Point(x1,y2);
        bool flag = false;
        if (inter(line,Line(tmp[0],tmp[1]))) flag = true;
        if (inter(line,Line(tmp[1],tmp[2]))) flag = true;
        if (inter(line,Line(tmp[2],tmp[3]))) flag = true;
        if (inter(line,Line(tmp[3],tmp[0]))) flag = true;
        if (inConvexPoly(line.s,tmp,4) >= 0 && inConvexPoly(line.e,tmp,4) >= 0) flag = true;
        printf("%s\n",flag ? "T" : "F");
    }
    return 0;
}
View Code

****POJ 1696 Space Ant

这个题目涉及到极角排序,首先题意一只蚂蚁,只会向左转,现在给出平面上很多个点,求解一种走法,
能使得蚂蚁能经过的点最多,每个顶点该蚂蚁只能经过一次,且所行走的路线不能发生交叉.

那么可想到的方案就是最先找到Y坐标最小的点,每次尽量选择靠下方的点走。

所以涉及到当前所在点对其他未到达点的角度问题。kuangbin神用的排序方式很好。MARK学习下

#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
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const double eps = 1e-8;
int sgn(double x)
{
    if (fabs(x) < eps) return 0;
    if (x < 0) return -1;
    return 1;
}

struct Point
{
    double x,y;
    int idx;
    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;
    }
};

double dist(Point a,Point b)
{
    return sqrt((b - a) * (b - a));
}

const int MAXN = 110;
Point p[MAXN];
int pos;
bool cmp(Point a,Point b)//对p[pos]点计较排序
{
    double tmp = (a - p[pos]) ^ (b - p[pos]);
    if (sgn(tmp) == 0)
        return dist(p[pos],a) < dist(p[pos],b);
    else if (sgn(tmp) < 0) return false;
    else return true;
}

int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        int n;
        scanf("%d",&n);
        for (int i = 0 ; i < n ; i++)
        {
            scanf("%d%lf%lf",&p[i].idx,&p[i].x,&p[i].y);
            if (i != 0) if (p[i].y < p[0].y || (p[i].y == p[0].y && p[i].x < p[0].x))
                swap(p[0],p[i]);
        }
        pos = 0;
        for (int i = 1 ; i < n ; i++)
        {
            sort(p + i,p + n,cmp);
            pos++;
        }
        printf("%d",n);
        for (int i = 0 ; i < n ; i++)
            printf(" %d",p[i].idx);
        puts("");
    }
    return 0;
}
View Code

****POJ 3347 Kadj Squares

这个题挺厉害,首先可以直接解出每个正方形左右端点的横坐标。然后就化为区间覆盖问题

接触横坐标其实很简单。就是化为区间覆盖他的维护方式很厉害

#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
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const int MAXN = 110;
struct node
{
    int l,r;
    int len;
}src[MAXN];
bool del[MAXN];
int N;

int main()
{
    while (scanf("%d",&N) != EOF)
    {
        if (N == 0) break;
        for (int i = 1 ; i <= N ; i++)
        {
            scanf("%d",&src[i].len);
            src[i].l = 0;
            for (int j = 1 ; j < i ; j++)
                src[i].l = max(src[i].l,src[j].r - abs(src[i].len - src[j].len));
            src[i].r = src[i].l + 2 *  src[i].len;
        }
        //for (int i = 1 ; i <= N ; i++)printf("%d %d\n",src[i].l,src[i].r);
        memset(del,false,sizeof(del));
        for (int i = 1 ; i <= N ; i++)
        {
            for (int j = 1 ; j < i ; j++)
            {
                if (src[i].l < src[j].r && src[i].len < src[j].len)
                    src[i].l = src[j].r;
            }
            for (int j = i + 1 ; j <= N ; j++)
            {
                if (src[i].r > src[j].l && src[i].len < src[j].len)
                    src[i].r = src[j].l;
            }
        }
        bool first = true;
        for (int i = 1 ; i <= N ; i++)
        {
            if (src[i].l < src[i].r)
            {
                if (first) first = false;
                else putchar(' ');
                printf("%d",i);
            }
        }
        puts("");
    }
    return 0;
}
View Code

POJ 2826 An Easy Problem?!

这道题就是要仔细一点有多重情况

利用线段相交判定是否这个形状的图形被封住了一点水也装不下

#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
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const double eps = 1e-8;
const int INF = 1000000;
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;
    }
};

struct Line
{
    Point s,e;
    Line(){}
    Line(Point a,Point b)
    {
        s = a;
        e = b;
    }

    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);
    }
};

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

int main()
{
    int x1,y1,x2,y2,x3,y3,x4,y4;
    Line l1,l2;
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d%d%d%d%d%d%d",&x1,&y1,&x2,&y2,&x3,&y3,&x4,&y4);
        l1 = Line(Point(x1,y1),Point(x2,y2));
        l2 = Line(Point(x3,y3),Point(x4,y4));
        if ((sgn(l1.s.y - l1.e.y) == 0) ||  (sgn(l2.s.y - l2.e.y) == 0))
        {
            puts("0.00");
            continue;
        }
        if (sgn(l1.s.y - l1.e.y) < 0) swap(l1.s,l1.e);
        if (sgn(l2.s.y - l2.e.y) < 0) swap(l2.s,l2.e);
        if (inter(l1,l2) == false)
        {
            puts("0.00");
            continue;
        }
        if (inter(Line(l1.s,Point(l1.s.x,INF)),l2) == true)
        {
            puts("0.00");
            continue;
        }
        if (inter(Line(l2.s,Point(l2.s.x,INF)),l1) == true)
        {
            puts("0.00");
            continue;
        }
        pair<int,Point>res;
        double area;
        res = l1 & l2;
        Point ret = res.second;
        res = l1 & Line(Point(INF,l2.s.y),l2.s);
        Point ret1 = res.second;
        area = fabs(((l2.s - ret) ^ (ret1 - ret)) / 2.0);
        res = l2 & Line(Point(INF,l1.s.y),l1.s);
        Point ret2 = res.second;
        area = min(area,fabs(((l1.s - ret) ^ (ret2 - ret)) / 2.0));
        printf("%.2f\n",area + eps);
    }
    return 0;
}
View Code

POJ 1039 Pipe

直接暴力枚举2个点即可

#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
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const double eps = 1e-8;
const double INF = 1e14;
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;
    }
};

struct Line
{
    Point s,e;
    Line(){}
    Line(Point a,Point b)
    {
        s = a;
        e = b;
    }

    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);
    }
};

bool seg_inter_line(Line l1,Line l2) //line l1.seg l2;
{
    return sgn((l2.s - l1.e) ^ (l1.s - l1.e)) * sgn((l2.e - l1.e) ^ (l1.s - l1.e)) <= 0;
}

const int MAXN = 110;
Point up[MAXN],down[MAXN];
int n;

int main()
{
    while (scanf("%d",&n) != EOF)
    {
        if (n == 0) break;
        for (int i = 0 ; i < n ; i++)
        {
            scanf("%lf%lf",&up[i].x,&up[i].y);
            down[i] = up[i];
            down[i].y--;
        }
        bool flag = false;
        double ans = -INF;
        int k;
        for (int i = 0 ; i < n && !flag ; i++)
        {
            for (int j = i + 1 ; j < n && !flag ; j++)
            {
                for (k = 0 ; k < n ; k++)
                {
                    if (seg_inter_line(Line(up[i],down[j]),Line(up[k],down[k])) == false)
                        break;
                }
                if (k >= n)
                {
                    flag = true;
                    break;
                }
                if (k > max(i,j))
                {
                    if (seg_inter_line(Line(up[i],down[j]),Line(up[k - 1],up[k])))
                    {
                        pair<int,Point>ret = Line(up[i],down[j]) & Line(up[k - 1],up[k]);
                        ans = max(ans,ret.second.x);
                    }
                    if (seg_inter_line(Line(up[i],down[j]),Line(down[k - 1],down[k])))
                    {
                        pair<int,Point>ret = Line(up[i],down[j]) & Line(down[k - 1],down[k]);
                        ans = max(ans,ret.second.x);
                    }
                }

                for (k = 0 ; k < n ; k++)
                {
                    if (seg_inter_line(Line(down[i],up[j]),Line(down[k],up[k])) == false)
                        break;
                }
                if (k >= n)
                {
                    flag = true;
                    break;
                }
                if (k > max(i,j))
                {
                    if (seg_inter_line(Line(down[i],up[j]),Line(up[k],up[k - 1])) == true)
                    {
                        pair<int,Point>ret = Line(down[i],up[j]) & Line(up[k],up[k - 1]);
                        ans = max(ans,ret.second.x);
                    }
                    if (seg_inter_line(Line(down[i],up[j]),Line(down[k],down[k - 1])) == true)
                    {
                        pair<int,Point>ret = Line(down[i],up[j]) & Line(down[k],down[k - 1]);
                        ans = max(ans,ret.second.x);
                    }
                }
            }
        }
        if (flag) puts("Through all the pipe.");
        else printf("%.2f\n",ans);
    }
    return 0;
}
View Code

POJ 3449 Geometric Shapes

暴力判相交。这里有个知识

**给出坐标轴上1个正方形对角线上的2个点

求另外2个点的最简单方法

这4个方程可解

x1+x3 = x0+x2;
x1-x3  =  y2-y0;
y1+y3 =  y0+y2;
y1-y3 =  x0-x2;
#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
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const double eps = 1e-8;
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;
    }
};

struct Line
{
    Point s,e;
    Line(){}
    Line(Point a,Point b)
    {
        s = a;
        e = b;
    }
};

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

const int MAXN = 30;
struct node
{
    char id;
    int n;
    Point p[MAXN];
    friend bool operator < (const node &a,const node &b)
    {
        return a.id < b.id;
    }
}src[MAXN];


char str[MAXN];
bool check(node a,node b)
{
    for (int i = 0 ; i < a.n ; i++)
    {
        for (int j = 0 ; j < b.n ; j++)
        {
            if (inter(Line(a.p[i],a.p[(i + 1) % a.n]),Line(b.p[j],b.p[(j + 1) % b.n])))
                return true;
        }
    }
    return false;
}

bool flag[MAXN];
int main()
{
    int n;
    while (scanf("%s",str) != EOF)
    {
        if (str[0] == '.') break;
        n = 0;
        src[0].id = str[0];
        scanf("%s",str);
        if (strcmp(str,"square") == 0)
        {
            src[0].n = 4;
            scanf(" (%lf,%lf)",&src[0].p[0].x,&src[0].p[0].y);
            scanf(" (%lf,%lf)",&src[0].p[2].x,&src[0].p[2].y);
            src[0].p[1].x = ((src[0].p[0].x + src[0].p[2].x) + (src[0].p[2].y - src[0].p[0].y)) / 2;
            src[0].p[1].y = ((src[0].p[0].y + src[0].p[2].y) + (src[0].p[0].x - src[0].p[2].x)) / 2;
            src[0].p[3].x = ((src[0].p[0].x + src[0].p[2].x) - (src[0].p[2].y - src[0].p[0].y)) / 2;
            src[0].p[3].y = ((src[0].p[0].y + src[0].p[2].y) - (src[0].p[0].x - src[0].p[2].x)) / 2;
        }
        else if (strcmp(str,"line") == 0)
        {
            src[0].n = 2;
            scanf(" (%lf,%lf)",&src[0].p[0].x,&src[0].p[0].y);
            scanf(" (%lf,%lf)",&src[0].p[1].x,&src[0].p[1].y);
        }
        else if (strcmp(str,"triangle") == 0)
        {
            src[0].n = 3;
            scanf(" (%lf,%lf)",&src[0].p[0].x,&src[0].p[0].y);
            scanf(" (%lf,%lf)",&src[0].p[1].x,&src[0].p[1].y);
            scanf(" (%lf,%lf)",&src[0].p[2].x,&src[0].p[2].y);
        }
        else if (strcmp(str,"rectangle") == 0)
        {
            src[0].n = 4;
            scanf(" (%lf,%lf)",&src[0].p[0].x,&src[0].p[0].y);
            scanf(" (%lf,%lf)",&src[0].p[1].x,&src[0].p[1].y);
            scanf(" (%lf,%lf)",&src[0].p[2].x,&src[0].p[2].y);
            src[0].p[3].x = src[0].p[2].x + src[0].p[0].x - src[0].p[1].x;
            src[0].p[3].y = src[0].p[2].y + src[0].p[0].y - src[0].p[1].y;
        }
        else if(strcmp(str,"polygon") == 0)
        {
            scanf("%d",&src[0].n);
            for (int i = 0 ; i <= src[0].n ; i++)
                scanf(" (%lf,%lf)",&src[0].p[i].x,&src[0].p[i].y);
        }
        n = 1;
        while (scanf("%s",str) != EOF)
        {
            if (str[0] == '-') break;
            src[n].id = str[0];
            scanf("%s",str);
            if (strcmp(str,"square") == 0)
            {
                src[n].n = 4;
                scanf(" (%lf,%lf)",&src[n].p[0].x,&src[n].p[0].y);
                scanf(" (%lf,%lf)",&src[n].p[2].x,&src[n].p[2].y);
                src[n].p[1].x = ((src[n].p[0].x + src[n].p[2].x) + (src[n].p[2].y - src[n].p[0].y)) / 2;
                src[n].p[1].y = ((src[n].p[0].y + src[n].p[2].y) + (src[n].p[0].x - src[n].p[2].x)) / 2;
                src[n].p[3].x = ((src[n].p[0].x + src[n].p[2].x) - (src[n].p[2].y - src[n].p[0].y)) / 2;
                src[n].p[3].y = ((src[n].p[0].y + src[n].p[2].y) - (src[n].p[0].x - src[n].p[2].x)) / 2;
            }
            else if (strcmp(str,"line") == 0)
            {
                src[n].n = 2;
                scanf(" (%lf,%lf)",&src[n].p[0].x,&src[n].p[0].y);
                scanf(" (%lf,%lf)",&src[n].p[1].x,&src[n].p[1].y);
            }
            else if (strcmp(str,"triangle") == 0)
            {
                src[n].n = 3;
                scanf(" (%lf,%lf)",&src[n].p[0].x,&src[n].p[0].y);
                scanf(" (%lf,%lf)",&src[n].p[1].x,&src[n].p[1].y);
                scanf(" (%lf,%lf)",&src[n].p[2].x,&src[n].p[2].y);
            }
            else if (strcmp(str,"rectangle") == 0)
            {
                src[n].n = 4;
                scanf(" (%lf,%lf)",&src[n].p[0].x,&src[n].p[0].y);
                scanf(" (%lf,%lf)",&src[n].p[1].x,&src[n].p[1].y);
                scanf(" (%lf,%lf)",&src[n].p[2].x,&src[n].p[2].y);
                src[n].p[3].x = src[n].p[2].x + src[n].p[0].x - src[n].p[1].x;
                src[n].p[3].y = src[n].p[2].y + src[n].p[0].y - src[n].p[1].y;
            }
            else if(strcmp(str,"polygon") == 0)
            {
                scanf("%d",&src[n].n);
                for (int i = 0 ; i <= src[n].n ; i++)
                    scanf(" (%lf,%lf)",&src[n].p[i].x,&src[n].p[i].y);
            }
            n++;
        }
        sort(src,src + n);
        for (int i = 0 ; i < n ; i++)
        {
            printf("%c ",src[i].id);
            memset(flag,false,sizeof(flag));
            int cnt = 0;
            for (int j = 0 ; j < n ; j++)
            {
                if (i == j) continue;
                if (check(src[i],src[j]))
                {
                    cnt++;
                    flag[j] = true;
                }
            }
            if (cnt == 0) puts("has no intersections");
            else if (cnt == 1)
            {
                printf("intersects with ");
                for (int j = 0 ; j < n ; j++)
                {
                    if (flag[j])
                    {
                        printf("%c\n",src[j].id);
                        break;
                    }
                }
            }
            else if (cnt == 2)
            {
                printf("intersects with ");
                for (int j = 0 ; j < n ; j++)
                {
                    if (flag[j])
                    {
                        if(cnt == 2)printf("%c ",src[j].id);
                        if(cnt == 1)printf("and %c\n",src[j].id);
                        cnt--;
                    }
                }
            }
            else
            {
                printf("intersects with ");
                for (int j = 0 ; j < n ; j++)
                {
                    if (flag[j])
                    {
                        if(cnt > 1)printf("%c, ",src[j].id);
                        if(cnt == 1)printf("and %c\n",src[j].id);
                        cnt--;
                    }
                }
            }
        }
        puts("");
    }
    return 0;
}
View Code

 

POJ 1584 A Round Peg in a Ground Hole

凸多边形判定通过点到直线距离判园是否在凸多边形内

#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
using namespace std;
int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
const double eps = 1e-8;
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;
    }
};

struct Line
{
    Point s,e;
    Line(){}
    Line(Point a,Point b)
    {
        s = a;
        e = b;
    }
};

double dist(Point a,Point b)
{
    return sqrt((b - a) * (b - a));
}

//判断凸多边形
//允许共线边
//点可以是顺时针给出也可以是逆时针给出
//点的编号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;
}

const int MAXN = 110;
Point src[MAXN];
int n;

int main()
{
    double R,X,Y;
    while (scanf("%d",&n) != EOF)
    {
        if (n < 3) break;
        scanf("%lf%lf%lf",&R,&X,&Y);
        for (int i = 0 ; i < n ; i++)
            scanf("%lf%lf",&src[i].x,&src[i].y);
        if (!isconvex(src,n))
        {
            printf("HOLE IS ILL-FORMED\n");
            continue;
        }
        Point P = Point(X,Y);
        if(inPoly(P,src,n) < 0)
        {
            printf("PEG WILL NOT FIT\n");
            continue;
        }
        bool flag = true;
        for (int i = 0 ; i < n ; i++)
        {
            if(sgn(dist(P,NearestPointToLineSeg(P,Line(src[i],src[(i + 1) % n]))) - R) < 0 )
            {
                flag = false;
                break;
            }
        }
        if(flag)printf("PEG WILL FIT\n");
        else printf("PEG WILL NOT FIT\n");
    }
    return 0;
}
View Code

 

posted @ 2015-11-28 16:38  Commence  阅读(419)  评论(0编辑  收藏  举报