【计算几何】

计算几何第一题:POJ-2318-TOYS

题意
用 n 条 总 左 到 右 排 好 序 的 直 线 分 成 将 一 个 长 方 形 分 成 n + 1 个 区 域 用n条总左到右排好序的直线分成将一个长方形分成n+1个区域 n线n+1
给 你 m 个 点 , 统 计 每 个 区 域 内 点 的 个 数 给你m个点,统计每个区域内点的个数 m
1 &lt; = n , m &lt; = 5 e 3 1&lt;=n,m&lt;=5e3 1<=n,m<=5e3
做法
我 们 考 虑 我们考虑 n^2 的 做 法 即 可 , 从 左 到 右 扫 描 每 条 线 的做法即可,从左到右扫描每条线 线
判 断 当 前 点 是 否 在 这 条 线 左 侧 , 在 左 侧 则 计 数 并 b r e a k 判断当前点是否在这条线左侧,在左侧则计数并break 线break
代码

#include <stdio.h>
#include <math.h>
#include <iostream>
#include <algorithm>
using namespace std;
#define dbg(x) cout<<#x<<" = "<<x<<endl

const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxn = 5005;
const int maxp = 1010;
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 &b) const
    {
        return Point(x - b.x, y - b.y);
    }
    double 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 relation(Point p)//判断点与直线的关系,1在左侧,2在右侧,3在直线上
    {
        int c = sgn( (p - s) ^ (e - s) );
        if (c < 0) return 1;
        else if (c > 0) return 2;
        return 3;
    }
};
Line l[maxn];
int sum[maxn];
int main()
{
    int n,m;
    int flag=0;
    double x,y,xa,ya,xb,yb,up,down;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)  break;
        else if(flag==0)  flag=1;
        else puts("");
        for(int i=0; i<=n; i++) sum[i]=0;
        scanf("%d%lf%lf%lf%lf",&m,&xa,&ya,&xb,&yb);
        for(int i=0;i<n;i++)
        {
            scanf("%lf%lf",&up,&down);
            l[i]=Line(Point(up,ya),Point(down,yb));
        }
        l[n]=Line(Point(xb,ya),Point(xb,yb));
        for(int i=0;i<m;i++)
        {
            scanf("%lf%lf",&x,&y);
            for(int j=0;j<=n;j++)
            {
                if(l[j].relation(Point(x,y))==2)
                {
                    sum[j]++;
                    break;
                }
            }
        }
        for(int i=0; i<=n; i++) printf("%d: %d\n",i,sum[i]);
    }
    return 0;
}

计算几何第二题:POJ-2398-Toy Storage

题意
用 n 条 直 线 分 成 将 一 个 长 方 形 分 成 n + 1 个 区 域 , 给 你 m 个 点 , 统 计 每 个 区 域 内 点 的 个 数 用n条直线分成将一个长方形分成n+1个区域,给你m个点,统计每个区域内点的个数 n线n+1m
1 &lt; = n , m &lt; = 1 e 3 1&lt;=n,m&lt;=1e3 1<=n,m<=1e3
做法
我 们 可 以 按 照 n 条 直 线 与 上 界 的 交 点 对 n 条 直 线 排 序 , 之 后 暴 力 扫 描 看 他 在 哪 个 区 域 即 可 。 我们可以按照n条直线与上界的交点对n条直线排序,之后暴力扫描看他在哪个区域即可。 n线n线
代码

#include <stdio.h>
#include <math.h>
#include <iostream>
#include <algorithm>
using namespace std;
#define dbg(x) cout<<#x<<" = "<<x<<endl

const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxn = 5005;
const int maxp = 1010;
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;
    }
    bool operator == (Point b) const
    {
        return sgn(x-b.x)==0&&sgn(y-b.y)==0;
    }
    bool operator < (Point b) const
    {
        return sgn(x-b.x)==0?sgn(y-b.y)<0:x<b.x;
    }
    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;
    }
};
struct Line
{
    Point s, e;
    Line() {}
    Line(Point _s, Point _e)
    {
        s = _s, e = _e;
    }
    bool operator <(const Line &b) const
    {
        if(s==b.s) return e<b.e;
        return s<b.s;
    }
    int relation(Point p)//判断点与直线的关系,1在左侧,2在右侧,3在直线上
    {
        int c = sgn( (p - s) ^ (e - s) );
        if (c < 0) return 1;
        else if (c > 0) return 2;
        return 3;
    }
};
Line l[maxn];
int sum[maxn];
int ans[maxn];
int main()
{
    int n,m;
    double x,y,xa,ya,xb,yb,up,down;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)  break;
        scanf("%d%lf%lf%lf%lf",&m,&xa,&ya,&xb,&yb);
        for(int i=0;i<=max(n,m); i++)
        {
            sum[i]=0;
            ans[i]=0;
        }
        for(int i=0;i<n;i++)
        {
            scanf("%lf%lf",&up,&down);
            l[i]=Line(Point(up,ya),Point(down,yb));
        }
        l[n]=Line(Point(xb,ya),Point(xb,yb));
        sort(l,l+1+n);
        for(int i=0;i<m;i++)
        {
            scanf("%lf%lf",&x,&y);
            for(int j=0;j<=n;j++)
            {
                if(l[j].relation(Point(x,y))==2)
                {
                    sum[j]++;
                    break;
                }
            }
        }
        for(int i=0;i<=n;i++) ans[sum[i]]++;
        printf("Box\n");
        for(int i=1;i<=n;i++) if(ans[i]) printf("%d: %d\n",i,ans[i]);
    }
    return 0;
}

计算几何第三题:POJ-3304-Segments

题意
给 你 n 条 线 段 , 求 是 否 有 一 条 直 线 , 满 足 所 有 直 线 在 其 上 面 的 投 影 有 公 共 的 交 点 给你n条线段,求是否有一条直线,满足所有直线在其上面的投影有公共的交点 n线线线
1 &lt; = n &lt; = 100 1&lt;=n&lt;=100 1<=n<=100
做法
首 先 如 果 投 影 有 公 共 的 交 点 , 那 么 如 果 在 那 个 公 共 的 交 点 上 做 垂 线 首先如果投影有公共的交点,那么如果在那个公共的交点上做垂线 线
肯 定 会 穿 过 n 条 线 段 , 所 以 我 们 只 要 看 是 否 存 在 一 条 直 线 与 所 有 线 段 都 相 交 即 可 肯定会穿过n条线段,所以我们只要看是否存在一条直线与所有线段都相交即可 穿n线线线
而 与 这 n 条 线 断 都 相 交 的 直 线 一 定 经 过 某 两 个 线 段 的 端 点 而与这n条线断都相交的直线一定经过某两个线段的端点 n线线线
我 们 假 设 这 条 直 线 不 经 过 任 意 一 个 端 点 , 我 们 一 定 可 以 平 移 这 条 直 线 使 它 达 到 某 个 端 点 再 停 止 我们假设这条直线不经过任意一个端点,我们一定可以平移这条直线使它达到某个端点再停止 线线使
之 后 在 那 个 端 点 上 旋 转 使 之 达 到 另 一 个 端 点 停 止 , 也 就 是 说 如 果 存 在 这 样 一 条 直 线 之后在那个端点上旋转使之达到另一个端点停止,也就是说如果存在这样一条直线 使线
我 们 只 要 枚 举 所 有 的 两 个 端 点 所 确 定 的 直 线 , 其 中 一 定 会 有 满 足 的 情 况 我们只要枚举所有的两个端点所确定的直线,其中一定会有满足的情况 线
所 以 我 们 只 要 所以我们只要 O(n^2) 枚 举 所 有 直 线 再 枚举所有直线再 线o(n)check 是 否 所 有 线 段 都 与 这 条 直 线 相 交 即 可 。 是否所有线段都与这条直线相交即可。 线线
代码

#include <stdio.h>
#include <math.h>
#include <iostream>
#include <algorithm>
using namespace std;

const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxn = 1005;
const int maxp = 1010;
int sgn(double x)
{
    if (fabs(x) <eps) return 0;
    if(x <0) return -1;
    return 1;
}
inline double sqr(double x)
{
    return x * x;
}
struct Point
{
    double x, y;
    Point() {}
    Point (double _x, double _y)
    {
        x = _x, y = _y;
    }
    void input()
    {
        scanf("%lf%lf", &x, &y);
    }
    void output()
    {
        printf("%.2f %.2f\n", x, y);
    }
    bool operator == (Point b) const
    {
        return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
    }
    bool operator < (Point b) const
    {
        return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
    }
    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 len()
    {
        return hypot(x, y);
    }
    double len2()
    {
        return x * x + y * y;
    }
    double distance(Point p)
    {
        return hypot(x - p.x, y - p.y);
    }
    Point operator + (const Point &b) const
    {
        return Point(x + b.x, y + b.y);
    }
    Point operator * (const double &k) const
    {
        return Point(x * k, y * k);
    }
    Point operator / (const double &k) const
    {
        return Point (x / k, y / k);
    }
    double rad(Point a, Point b)
    {
        Point p = *this;
        return fabs(atan2( fabs((a - p) ^ (b - p)), (a - p) * (b - p) ));
    }
    Point trunc(double r)
    {
        double l = len();
        if (!sgn(l)) return *this;
        r /= l;
        return Point(x * r, y * r);
    }
};
struct Line
{
    Point s, e;
    Line() {}
    Line(Point _s, Point _e)
    {
        s = _s, e = _e;
    }
    bool operator == (Line v)
    {
        return (s == v.s) && (e == v.e);
    }
    Line (Point p, double angle)
    {
        s = p;
        if (sgn(angle - pi / 2) == 0)
            e = (s + Point (0, 1));
        else
            e = (s + Point (1, tan(angle)));
    }
    Line(double a, double b, double c)
    {
        if (sgn(a) == 0)
        {
            s = Point(0, -c / b);
            e = Point(1, -c / b);
        }
        else if (sgn(b) == 0)
        {
            s = Point(-c / a, 0);
            e = Point(-c / a, 1);
        }
        else
        {
            s = Point(0, -c / b);
            e = Point(1, (-c-a) / b);
        }
    }
    void input()
    {
        s.input();
        e.input();
    }
    void adjust()
    {
        if (e < s) swap(s, e);
    }
    double length()
    {
        return s.distance(e);
    }
    double angle()
    {
        double k = atan2(e.y - s.y, e.x - s.x);
        if (sgn(k) < 0) k += pi;
        if (sgn(k - pi) == 0) k -= pi;
        return k;
    }
    int relation(Point p)
    {
        int c = sgn( (p - s) ^ (e - s) );
        if (c < 0) return 1;
        else if (c > 0) return 2;
        return 3;
    }
    bool pointonseg(Point p)
    {
        return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s) * (p - e)) <= 0;
    }
    bool parallel(Line v)
    {
        return sgn((e - s) ^ (v.e - v.s)) == 0;
    }
    Point lineprog(Point p)
    {
        return s + ( ((e - s) * ((e - s) * (p - s))) / ((e - s).len2()) );
    }
    Point symmetrypoint(Point p)
    {
        Point q = lineprog(p);
        return Point(2.0 * q.x - p.x, 2.0 * q.y - p.y);
    }
    double dispointtoline(Point p)
    {
        return fabs((p - s) ^ (e - s)) / length();
    }
    int linecrossseg(Line v)
    {
        int d1=sgn((e-s)^(v.s-s));
        int d2=sgn((e-s)^(v.e-s));
        if((d1^d2)==-2) return 2;
        return (d1==0||d2==0);
    }
};
Point p[maxn];
Line L[maxn];
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        double xa,ya,xb,yb;
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
             scanf("%lf%lf%lf%lf",&xa,&ya,&xb,&yb);
             p[i]=Point(xa,ya);
             p[i+n]=Point(xb,yb);
             L[i]=Line(p[i],p[i+n]);
        }
        int ff=0;
        for(int i=1;i<=2*n;i++)
        {
            for(int j=i;j<=2*n;j++)
            {
                if(p[i]==p[j]) continue;//防止出现两个点重合的情况
                Line now(p[i],p[j]);
                int flag=0;
                for(int k=1;k<=n;k++)
                {
                    if(now.linecrossseg(L[k])==0)
                    {
                        flag=1;
                        break;
                    }
                }
                if(flag==0)
                {
                    ff=1;
                    break;
                }
            }
            if(ff==1) break;
        }
        if(ff==1) puts("Yes!");
        else puts("No!");
    }
    return 0;
}

计算几何第四题:POJ-1269-Intersecting Lines

题意
给 你 一 对 直 线 , 判 断 两 条 位 置 关 系 给你一对直线,判断两条位置关系 线
做法
先 用 叉 积 判 断 两 条 直 线 是 否 平 行 先用叉积判断两条直线是否平行 线
如 果 不 平 行 则 是 相 交 , 平 行 的 话 判 一 下 一 条 直 线 上 的 点 是 否 在 另 一 条 直 线 上 如果不平行则是相交,平行的话判一下一条直线上的点是否在另一条直线上 线线
若 在 则 是 重 合 , 不 在 则 是 平 行 , 。 若在则是重合,不在则是平行,。
代码

#include <stdio.h>
#include <math.h>
#include <iostream>
#include <algorithm>
using namespace std;

const  double eps = 1e-12;
const  double inf = 1e20;
const  double pi = acos(-1.0);
const int maxp = 1010;
int sgn( double x) {
    if (fabs(x) <eps) return 0;
    if(x <0) return -1;
    return 1;
}
inline  double sqr( double x) { return x * x;}
struct Point {
     double x, y;
    Point() {}
    Point ( double _x,  double _y) {x = _x, y = _y;}
    void input() {scanf("%Lf%Lf", &x, &y);}
    void output() {cout << x << " " << y << endl; }
    bool operator == (Point b) const {return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;}
    bool operator < (Point b) const {return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;}
    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  len() {return hypot(x, y);}
    double  len2() {return x * x + y * y;}
    double  distance(Point p) {return hypot(x - p.x, y - p.y);}
    Point operator + (const Point &b) const {return Point(x + b.x, y + b.y);}
    Point operator * (const double  &k) const {return Point(x * k, y * k);}
    Point operator / (const double  &k) const {return Point (x / k, y / k);}
    double  rad(Point a, Point b) {
        Point p = *this;
        return fabs(atan2( fabs((a - p) ^ (b - p)), (a - p) * (b - p) ));
    }
    Point trunc(double  r) {
        double  l = len();
        if (!sgn(l)) return *this;
        r /= l;
        return Point(x * r, y * r);
    }
};
struct Line {
    Point s, e;
    Line() {}
    Line(Point _s, Point _e) {s = _s, e = _e;}
    bool operator == (Line v) {return (s == v.s) && (e == v.e);}
    Line (Point p, double  angle) {
        s = p;
        if (sgn(angle - pi / 2) == 0)
            e = (s + Point (0, 1));
        else
            e = (s + Point (1, tan(angle)));
    }
    Line(double  a, double  b, double  c) {
        if (sgn(a) == 0) {
            s = Point(0, -c / b);
            e = Point(1, -c / b);
        }
        else if (sgn(b) == 0) {
            s = Point(-c / a, 0);
            e = Point(-c / a, 1);
        }
        else {
            s = Point(0, -c / b);
            e = Point(1, (-c-a) / b);
        }
    }
    Point getV() {return e-s;}
    void input() {s.input(); e.input();}
    void adjust() {if (e < s) swap(s, e);}
    double  length() {return s.distance(e);}
    double  angle() {
        double  k = atan2(e.y - s.y, e.x - s.x);
        if (sgn(k) < 0) k += pi;
        if (sgn(k - pi) == 0) k -= pi;
        return k;
    }
    int relation(Point p) {
        int c = sgn( (p - s) ^ (e - s) );
        if (c < 0) return 1;
        else if (c > 0) return 2;
        return 3;
    }
    bool pointonseg(Point p) {
        return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s) * (p - e)) <= 0;
    }
    bool parallel(Line v) {return sgn((e - s) ^ (v.e - v.s)) == 0;}
    Point lineprog(Point p) {
        return s + ( ((e - s) * ((e - s) * (p - s))) / ((e - s).len2()) );
    }
    Point symmetrypoint(Point p) {
        Point q = lineprog(p);
        return Point(2.0 * q.x - p.x, 2.0 * q.y - p.y);
    }
    double  dispointtoline(Point p) {return fabs((p - s) ^ (e - s)) / length();}
    double  dispointtoseg(Point p) {
        if (sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0)
            return min(p.distance(s), p.distance(e));
        return dispointtoline(p);
    }
    int linecrossline(Line v)
    {
        if((*this).parallel(v)) return v.relation(s)==3;
        return 2;
    }
    Point crosspoint(Line v)
    {
        double a1=(v.e-v.s)^(s-v.s);
        double a2=(v.e-v.s)^(e-v.s);
        return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
    }
};
int main()
{
    int n;
    double xa,xb,ya,yb,xc,yc,xd,yd;
    while(scanf("%d",&n)!=EOF)
    {
        printf("INTERSECTING LINES OUTPUT\n");
        while(n--)
        {
            scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&xa,&ya,&xb,&yb,&xc,&yc,&xd,&yd);
            Line L1(Point(xa,ya),Point(xb,yb));
            Line L2(Point(xc,yc),Point(xd,yd));
            int tmp=L1.linecrossline(L2);
            if(tmp==0) printf("NONE\n");
            else if(tmp==1) printf("LINE\n");
            else
            {
                Point ans=L1.crosspoint(L2);
                printf("POINT %.2f %.2f\n",ans.x,ans.y);
            }
        }
        printf("END OF OUTPUT\n");
    }
}

计算几何第五题:POJ-1556-The Doors

题意
一 个 房 间 内 有 平 行 的 n 堵 墙 , 每 个 墙 上 有 两 道 门 , 求 从 起 点 走 到 终 点 的 最 短 路 径 。 一个房间内有平行的n堵墙,每个墙上有两道门,求从起点走到终点的最短路径。 n
例如下图:
在这里插入图片描述
做法
可 以 到 某 个 门 的 最 短 距 离 一 定 是 由 某 个 门 的 两 端 点 出 发 的 可以到某个门的最短距离一定是由某个门的两端点出发的
所 以 我 们 只 要 从 左 到 右 算 出 到 达 每 个 点 的 最 短 距 离 所以我们只要从左到右算出到达每个点的最短距离
每 个 点 用 所 有 之 前 可 以 直 接 到 达 这 个 点 的 点 去 松 弛 这 个 点 , 复 杂 度 O ( n 3 ) 每个点用所有之前可以直接到达这个点的点去松弛这个点,复杂度O(n^3) O(n3)
代码

#include <stdio.h>
#include <math.h>
#include <iostream>
#include <algorithm>
using namespace std;

const  double eps = 1e-12;
const  double inf = 1e20;
const  double pi = acos(-1.0);
const int maxp = 1010;
int sgn( double x)
{
    if (fabs(x) <eps) return 0;
    if(x <0) return -1;
    return 1;
}
inline  double sqr( double x)
{
    return x * x;
}
struct Point
{
    double x, y;
    Point() {}
    Point ( double _x,  double _y)
    {
        x = _x, y = _y;
    }
    void input()
    {
        scanf("%lf%lf", &x, &y);
    }
    void output()
    {
        cout <<"x= "<<x << " y= " << y << endl;
    }
    bool operator == (Point b) const
    {
        return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
    }
    bool operator < (Point b) const
    {
        return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
    }
    Point operator - (const Point &b) const
    {
        return Point(x - b.x, y - b.y);
    }
    //叉积  |a||b|sin
    double  operator ^ (const Point &b) const
    {
        return x * b.y - y * b.x;
    }
    //点积 |a||b|cos 向量点积之后反过来求夹角
    double  operator * (const Point & b) const
    {
        return x * b.x + y * b.y;
    }
    //利用库函数计算点到(0,0)的距离
    double  len()
    {
        return hypot(x, y);
    }
    //返回长度的平方
    double  len2()
    {
        return x * x + y * y;
    }
    //返回两点间距离
    double  distance(Point p)
    {
        return hypot(x - p.x, y - p.y);
    }
    //向量加法
    Point operator + (const Point &b) const
    {
        return Point(x + b.x, y + b.y);
    }
    //向量乘常数
    Point operator * (const double  &k) const
    {
        return Point(x * k, y * k);
    }
    //向量除以常数
    Point operator / (const double  &k) const
    {
        return Point (x / k, y / k);
    }
    //求a,b以当前点为中间点的角
    double  rad(Point a, Point b)
    {
        Point p = *this;
        return fabs(atan2( fabs((a - p) ^ (b - p)), (a - p) * (b - p) ));
    }
    //转换为长度为r的向量
    Point trunc(double  r)
    {
        double  l = len();
        if (!sgn(l)) return *this;
        r /= l;
        return Point(x * r, y * r);
    }
};
struct Line
{
    Point s, e;
    Line() {}
    Line(Point _s, Point _e)
    {
        s = _s, e = _e;
    }
    //直线判断重合
    bool operator == (Line v)
    {
        return (s == v.s) && (e == v.e);
    }
    //根据一个点和倾斜角angle确定直线,0<=angle<pi
    Line (Point p, double  angle)
    {
        s = p;
        if (sgn(angle - pi / 2) == 0)
            e = (s + Point (0, 1));
        else
            e = (s + Point (1, tan(angle)));
    }
    //ax+by+c确定直线
    Line(double  a, double  b, double  c)
    {
        if (sgn(a) == 0)
        {
            s = Point(0, -c / b);
            e = Point(1, -c / b);
        }
        else if (sgn(b) == 0)
        {
            s = Point(-c / a, 0);
            e = Point(-c / a, 1);
        }
        else
        {
            s = Point(0, -c / b);
            e = Point(1, (-c-a) / b);
        }
    }
    //得到s-e方向单位向量
    Point getV()
    {
        return e-s;
    }
    void input()
    {
        s.input();
        e.input();
    }
    void adjust()
    {
        if (e < s) swap(s, e);
    }
    //返回线段的长度
    double  length()
    {
        return s.distance(e);
    }
    //返回直线倾斜角
    double  angle()
    {
        double  k = atan2(e.y - s.y, e.x - s.x);
        if (sgn(k) < 0) k += pi;
        if (sgn(k - pi) == 0) k -= pi;
        return k;
    }
    //点和直线关系
    //1  在左侧
    //2  在右侧
    //3  在直线上
    int relation(Point p)
    {
        int c = sgn( (p - s) ^ (e - s) );
        if (c < 0) return 1;
        else if (c > 0) return 2;
        return 3;
    }
    //点在线段上的判断
    bool pointonseg(Point p)
    {
        return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s) * (p - e)) <= 0;
    }
    //判断量直线平行或重合
    bool parallel(Line v)
    {
        return sgn((e - s) ^ (v.e - v.s)) == 0;
    }
    //两线段相交判断
    //2 规范相交
    //1 非规范相交-过端点
    //0 不相交
    int segcrossseg(Line v)
    {
        int d1 = sgn((e-s)^(v.s-s));
        int d2 = sgn((e-s)^(v.e-s));
        int d3 = sgn((v.e-v.s)^(s-v.s));
        int d4 = sgn((v.e-v.s)^(e-v.s));
        if((d1^d2)==-2&&(d3^d4)==-2) return 2;
            return ((d1==0&&sgn((v.s-s)*(v.s-e))<=0)||(d2==0&&sgn((v.e-s)*(v.e-e))<=0)||(d3==0&&sgn((s-v.s)*(s-v.e))<=0)||(d4==0&&sgn((e-v.s)*(e-v.e))<=0));
    }

    Point lineprog(Point p)
    {
        return s + ( ((e - s) * ((e - s) * (p - s))) / ((e - s).len2()) );
    }
    Point symmetrypoint(Point p)
    {
        Point q = lineprog(p);
        return Point(2.0 * q.x - p.x, 2.0 * q.y - p.y);
    }
    double  dispointtoline(Point p)
    {
        return fabs((p - s) ^ (e - s)) / length();
    }
    double  dispointtoseg(Point p)
    {
        if (sgn((p-s)*(e-s))<0 || sgn((p-e)*(s-e))<0)
            return min(p.distance(s), p.distance(e));
        return dispointtoline(p);
    }
    //两直线关系
    //0 平行
    //1 重合
    //2 相交
    int linecrossline(Line v)
    {
        if((*this).parallel(v)) return v.relation(s)==3;
        return 2;
    }
    Point crosspoint(Line v)
    {
        double a1=(v.e-v.s)^(s-v.s);
        double a2=(v.e-v.s)^(e-v.s);
        return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
    }
};
const int maxn = 1005;
double dp[maxn];
Line seg[maxn];
Point p[maxn];
int pcnt,lcnt;
int main()
{
    double x,ya,yb,yc,yd;
    int n;
    while(scanf("%d",&n)!=EOF)
    {
       if(n==-1) break;
       pcnt=0,lcnt=0;
       p[++pcnt]=Point(0,5);
       for(int i=1;i<=n;i++)
       {
            scanf("%lf%lf%lf%lf%lf",&x,&ya,&yb,&yc,&yd);
            p[++pcnt]=Point(x,ya);
            p[++pcnt]=Point(x,yb);
            p[++pcnt]=Point(x,yc);
            p[++pcnt]=Point(x,yd);
            seg[++lcnt]=Line(Point(x,0),Point(x,ya));
            seg[++lcnt]=Line(Point(x,yb),Point(x,yc));
            seg[++lcnt]=Line(Point(x,yd),Point(x,10));
       }
       p[++pcnt]=Point(10,5);
       dp[1]=0.0;
       for(int i=2;i<=pcnt;i++) dp[i]=1e20;
       for(int i=2;i<=pcnt;i++)
       {
           for(int j=1;j<i;j++)
           {
               Line tmp(p[i],p[j]);
               int flag=0;
               for(int k=1;k<=(i-2)/4*3;k++)//对所有在这个点左边的线段判交,有交点则不能松弛
               {
                   if(seg[k].segcrossseg(tmp)==2)
                   {
                       flag=1;
                       break;
                   }
               }
               if(flag==0) dp[i]=min(dp[i],dp[j]+tmp.length());
           }
       }
       printf("%.2f\n",dp[pcnt]);
    }
}

计算几何第六题NWERC2017-Problem G-Glyph Recognition

题意
给 你 n 个 点 , 找 出 一 种 中 心 在 远 点 而 且 有 一 个 点 在 x 轴 上 的 正 多 边 形 环 覆 盖 这 些 点 给你n个点,找出一种中心在远点而且有一个点在x轴上的正多边形环覆盖这些点 nx
( 在 一 个 正 多 边 形 中 扣 去 一 个 与 他 相 似 的 且 平 行 的 正 多 边 形 ) (在一个正多边形中扣去一个与他相似的且平行的正多边形)
使 这 个 环 的 外 围 面 积 尽 量 小 , 内 围 面 积 尽 量 大 使这个环的外围面积尽量小,内围面积尽量大 使
正 多 边 形 为 正 3 − 8 边 形 , 求 内 部 面 积 与 外 部 面 积 的 最 大 比 值 正多边形为正3-8边形,求内部面积与外部面积的最大比值 38
做法
二 分 每 种 正 多 边 形 在 x 轴 上 点 的 横 坐 标 二分每种正多边形在x轴上点的横坐标 x
当 计 算 最 大 的 内 围 面 积 时 , 只 要 当 前 多 边 形 内 不 包 含 点 就 可 以 变 大 当计算最大的内围面积时,只要当前多边形内不包含点就可以变大
当 计 算 最 小 的 外 围 面 积 时 , 只 要 当 前 多 边 形 内 有 n 个 点 就 可 以 减 小 当计算最小的外围面积时,只要当前多边形内有n个点就可以减小 n
二 分 计 算 每 种 多 边 形 的 答 案 取 m a x 即 可 二分计算每种多边形的答案取max即可 max
构 造 多 边 形 用 点 根 据 原 点 旋 转 一 定 度 数 来 做 构造多边形用点根据原点旋转一定度数来做
判 一 个 点 是 否 在 多 边 形 内 部 只 需 判 定 他 在 这 个 多 边 形 所 有 向 量 的 左 侧 即 可 。 判一个点是否在多边形内部只需判定他在这个多边形所有向量的左侧即可。
代码

#include<iomanip>
#include<iostream>
#include<math.h>
using namespace std;
const long double eps= 1e-9;
const long double pi = acos(-1.0);
int sgn(long double x)
{
    if(fabs(x)<eps) return 0;
    if(x<0) return -1;
    else return 1;
}
struct Point
{
    long double x,y;
    Point(){}
    Point (long double _x,long double _y)
    {
        x=_x,y=_y;
    }
    Point operator -(const Point &b)const
    {
        return Point(x-b.x,y-b.y);
    }
    long double operator ^(const Point &b) const
    {
        return x*b.y-y*b.x;
    }
    Point rotat(Point p,double angle)
    {
        Point v=(*this)-p;
        double c=cos(angle),s=sin(angle);
        return Point(p.x+v.x*c-v.y*s,p.y+v.x*s+v.y*c);
    }
};
struct Line
{
    Point s,e;
    Line(){}
    Line(Point _s,Point _e)
    {
        s=_s,e=_e;
    }
    int relation(Point p)
    {
        int c=sgn((p-s)^(e-s));
        if(c<0) return 1;
        else if(c>0) return 2;
        else return 3;
    }
};
const int maxn = 1005;
int n;
Point p[maxn],pp[maxn];
Line l[maxn];
int check(long double mid,int pos)
{
    long double ang=2.0*pi/(1.0*pos);
    pp[0]=Point(mid,0.0);
    for(int i=1;i<pos;i++)   pp[i]=pp[i-1].rotat(Point(0,0),ang);//旋转获得每个点
    for(int i=0;i<pos-1;i++) l[i]=Line (pp[i],pp[i+1]);//按逆时针建边
    l[pos-1]=Line(pp[pos-1],pp[0]);
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        int flag=0;
        for(int j=0;j<pos;j++) if(l[j].relation(p[i])!=1){flag=1;break;}
        if(flag==0) cnt++;
    }
    return  cnt;
}
int main()
{
    ios::sync_with_stdio(false);
    int pos;
    long double up,ans=0;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>p[i].x>>p[i].y;
    for(int i=3;i<=8;i++)
    {
        long double l=0,r=1e10;
        while(r-l>=eps)
        {
            long double mid=(l+r)/2.0;
            if(check(mid,i)==0) l=mid;
            else r=mid;
        }
        up=l*l,l=0,r=1e10;
        while(r-l>=eps)
        {
            long double mid=(l+r)/2.0;
            if(check(mid,i)==n) r=mid;
            else l=mid;
        }
        if(up/(l*l)>ans) ans=up/(l*l),pos=i;
    }
    cout<<pos<<" "<<fixed<<setprecision(10)<<ans<<endl;
    return 0;
}

计算几何第七题POJ-2653-Pick-up sticks

题意
在 一 个 二 维 平 面 上 依 次 放 置 n 条 木 棍 , 问 最 后 没 有 被 覆 盖 的 木 棍 有 哪 些 , n &lt; = 1 e 5 , 答 案 &lt; = 1000 在一个二维平面上依次放置n条木棍,问最后没有被覆盖的木棍有哪些,n&lt;=1e5,答案&lt;=1000 n,n<=1e5,<=1000
做法
我 们 时 光 倒 流 一 下 , 从 后 往 前 做 这 道 题 我们时光倒流一下,从后往前做这道题
很 明 显 最 后 一 根 木 棍 一 定 是 在 最 上 面 的 , 那 么 这 条 木 棍 所 覆 盖 的 木 棍 一 定 都 是 被 覆 盖 的 很明显最后一根木棍一定是在最上面的,那么这条木棍所覆盖的木棍一定都是被覆盖的
依 次 递 推 就 能 求 出 所 有 被 最 后 一 条 木 棍 直 接 覆 盖 或 者 间 接 覆 盖 的 木 棍 依次递推就能求出所有被最后一条木棍直接覆盖或者间接覆盖的木棍
然 后 继 续 向 前 扫 描 到 一 个 没 有 被 覆 盖 的 木 棍 , 然 后 重 复 这 个 过 程 然后继续向前扫描到一个没有被覆盖的木棍,然后重复这个过程
这 样 就 可 以 得 到 所 有 在 最 顶 层 的 木 棍 , 如 果 我 们 用 v i s 标 记 被 覆 盖 木 棍 的 方 法 这样就可以得到所有在最顶层的木棍,如果我们用vis标记被覆盖木棍的方法 vis
时 间 复 杂 度 为 n 2 时间复杂度为n^2 n2
但 是 如 果 我 们 用 l i s t 里 面 的 l i s t 维 护 没 有 被 覆 盖 的 木 棍 , 时 间 复 杂 度 就 是 O ( n ∗ 1000 ) 。 但是如果我们用list里面的list维护没有被覆盖的木棍,时间复杂度就是O(n*1000)。 listlistO(n1000)
代码

#include<stdio.h>
#include<math.h>
#include<queue>
#include<list>
#include<iostream>
#include<algorithm>
using namespace std;
const  double eps = 1e-12;
const  double pi = acos(-1.0);
const int maxp = 1010;
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;
    }
    bool operator == (Point b) const
    {
        return sgn(x - b.x) == 0 && sgn(y - b.y) == 0;
    }
    bool operator < (Point b) const
    {
        return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
    }
    Point operator - (const Point &b) const
    {
        return Point(x - b.x, y - b.y);
    }
    //叉积  |a||b|sin
    double  operator ^ (const Point &b) const
    {
        return x * b.y - y * b.x;
    }
    //点积 |a||b|cos 向量点积之后反过来求夹角
    double  operator * (const Point & b) const
    {
        return x * b.x + y * b.y;
    }
    Point operator + (const Point &b) const
    {
        return Point(x + b.x, y + b.y);
    }
};
struct Line
{
    Point s, e;
    Line() {}
    Line(Point _s, Point _e)
    {
        s = _s, e = _e;
    }
    //两线段相交判断
    //2 规范相交
    //1 非规范相交-过端点
    //0 不相交
    int segcrossseg(Line v)
    {
        int d1 = sgn((e-s)^(v.s-s));
        int d2 = sgn((e-s)^(v.e-s));
        int d3 = sgn((v.e-v.s)^(s-v.s));
        int d4 = sgn((v.e-v.s)^(e-v.s));
        if((d1^d2)==-2&&(d3^d4)==-2) return 2;
            return ((d1==0&&sgn((v.s-s)*(v.s-e))<=0)||(d2==0&&sgn((v.e-s)*(v.e-e))<=0)||(d3==0&&sgn((s-v.s)*(s-v.e))<=0)||(d4==0&&sgn((e-v.s)*(e-v.e))<=0));
    }
};
const int maxn = 1e5+10;
Line l[maxn];
vector<int>ans;
list<int> L;
void del(list<int>::iterator it)//递归算出所有被当前线段所影响的线段
{
    Line now = l[*it];
    list<int>::iterator tmp=it;
    for(list<int>::iterator itt=(++it);itt!=L.end();)
    {
         Line nex = l[*itt];
         if(now.segcrossseg(nex))
         {
             del(itt);//找到之后先递归,再将本点删除
             itt=L.erase(itt);
         }
         else ++itt;
    }
    return ;
}
int main()
{
    int n;
    double xa,xb,ya,yb;
    while(scanf("%d",&n)!=EOF)
    {
        L.clear();
        ans.clear();
        if(n==0) break;
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf",&xa,&ya,&xb,&yb);
            l[i]=Line (Point(xa,ya),Point(xb,yb));
        }
        for(int i=n;i>=1;i--)
        {
            L.push_back(i);
        }
        for(list<int>::iterator it=L.begin();it!=L.end();)
        {
            list<int>::iterator tmp=it;
            del(it);
            it=++tmp;//由于有删除操作,要先存当前指针位置,在删除之后让迭代器指向当前的下一位
        }
        L.reverse();
        for(list<int>::iterator it=L.begin();it!=L.end();++it)
        {
            int tmp=*it;
            ans.push_back(tmp);
        }
         sort(ans.begin(),ans.end());//保证答案有序
         printf("Top sticks:");
        for(int i=0;i<ans.size();i++)
        {
            if(i!=ans.size()-1) printf(" %d,",ans[i]);
            else printf(" %d.\n",ans[i]);
        }
    }
    return 0;
}

目录 ㈠ 点的基本运算 1. 平面上两点之间距离 1 2. 判断两点是否重合 1 3. 矢量叉乘 1 4. 矢量点乘 2 5. 判断点是否在线段上 2 6. 求一点饶某点旋转后的坐标 2 7. 求矢量夹角 2 ㈡ 线段及直线的基本运算 1. 点与线段的关系 3 2. 求点到线段所在直线垂线的垂足 4 3. 点到线段的最近点 4 4. 点到线段所在直线的距离 4 5. 点到折线集的最近距离 4 6. 判断圆是否在多边形内 5 7. 求矢量夹角余弦 5 8. 求线段之间的夹角 5 9. 判断线段是否相交 6 10.判断线段是否相交但不交在端点处 6 11.求线段所在直线的方程 6 12.求直线的斜率 7 13.求直线的倾斜角 7 14.求点关于某直线的对称点 7 15.判断两条直线是否相交及求直线交点 7 16.判断线段是否相交,如果相交返回交点 7 ㈢ 多边形常用算法模块 1. 判断多边形是否简单多边形 8 2. 检查多边形顶点的凸凹性 9 3. 判断多边形是否凸多边形 9 4. 求多边形面积 9 5. 判断多边形顶点的排列方向,方法一 10 6. 判断多边形顶点的排列方向,方法二 10 7. 射线法判断点是否在多边形内 10 8. 判断点是否在凸多边形内 11 9. 寻找点集的graham算法 12 10.寻找点集凸包的卷包裹法 13 11.判断线段是否在多边形内 14 12.求简单多边形的重心 15 13.求凸多边形的重心 17 14.求肯定在给定多边形内的一个点 17 15.求从多边形外一点出发到该多边形的切线 18 16.判断多边形的核是否存在 19 ㈣ 圆的基本运算 1 .点是否在圆内 20 2 .求不共线的三点所确定的圆 21 ㈤ 矩形的基本运算 1.已知矩形三点坐标,求第4点坐标 22 ㈥ 常用算法的描述 22 ㈦ 补充 1.两圆关系: 24 2.判断圆是否在矩形内: 24 3.点到平面的距离: 25 4.点是否在直线同侧: 25 5.镜面反射线: 25 6.矩形包含: 26 7.两圆交点: 27 8.两圆公共面积: 28 9. 圆和直线关系: 29 10. 内切圆: 30 11. 求切点: 31 12. 线段的左右旋: 31 13.公式: 32
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值