专题:基础计算几何

A - POJ 2318 TOYS
思路:

利用叉积运算,判断点在直线的哪一侧,对于直线 AB O ,如果 向量OA×OB>0 则说明 O 在直线的左侧,以 AB 的方向作为界定。
所以对于每一个点,二分的找到所在的直线就行了!

代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
#define S first
#define E second
using namespace std;
const int N = 5e3 + 10;
struct Point
{
    int x, y;
    Point(int x = 0, int y = 0) :x(x), y(y){}
    Point operator - (const Point& p)
    {
        return Point(x - p.x, y - p.y);
    }
    int operator ^ (const Point& p)
    {
        return (x * p.y - y * p.x);
    }
};
Point UL, LR;
int n, m, ans[N];
pair<Point, Point> L[N];
Point a[N];
// 叉积判断
bool check(Point& S, Point& E, Point p)
{
    return ((S - p) ^ (E - p)) > 0;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    bool fg = 0;
    while(scanf("%d", &n), n)
    {
        scanf("%d%d%d%d%d", &m, &UL.x, &UL.y, &LR.x, &LR.y);
        int x, y;
        for(int i = 0;i < n;i ++) {
            scanf("%d%d", &x, &y);
            L[i].S = Point(x, UL.y);
            L[i].E = Point(y, LR.y);
        }
        L[n].S = Point(LR.x, UL.y), L[n].E = LR;
        memset(ans, 0, sizeof(ans));
        for(int i = 0;i < m;i ++) {
            scanf("%d%d", &x, &y);
            int l = 0, r = n;
            while(l <= r) {
                int mid = (l + r) >> 1;
                if(check(L[mid].S, L[mid].E, Point(x, y))) l = mid + 1;
                else r = mid - 1;
            }
            ans[l] ++;
        }
        if(fg) puts("");
        for(int i = 0;i <= n;i ++) printf("%d: %d\n", i, ans[i]);
        fg = 1;
    }
    return 0;
}

POJ 2398 Toy Storage
思路:

题意和上个题目一样,但是这个题给定的线段的顺序不一致,所以要把线段从左往右排一遍序,然后解法就和上一题一样了!


POJ 3304 Segments
思路:

首先,可以注意到,如果存在这样的一条穿过所有线段的直线,那么我们可以通过旋转直线使得这条满足条件的直线可以会通过两个端点!
知道这个后,我们就可以枚举两个端点,去确定一条直线,然后判断这条直线是否满足要求,就是判断直线是否与线段相交,具体就是判断是否满足

Cross(A,B,o1)Cross(A,B,o2)0

这题一个比较坑的地方就是:注意判断枚举的两个点不能重合!因为如果两个点重合了的话,那么对于所有的线段都满足相交的条件了。

代码:
#include <cstdio>
#include <algorithm>
#include <cmath>
#define S first
#define E second
#define eps 1e-8
using namespace std;
const int N = 1e2 + 10;
typedef double TP;
struct Point
{
    TP x, y;
    Point(TP x = 0, TP y = 0) :x(x), y(y){}
    Point operator - (const Point& p)
    {
        return Point(x - p.x, y - p.y);
    }
    TP operator ^ (const Point& p)
    {
        return (x * p.y - y * p.x);
    }
};
struct Line
{
    Point S, E;
    Line(Point _s = Point(), Point _e = Point()): S(_s), E(_e) {}
};
Line L[N];
int n;
int dcmp(double x)  //  
{  
    if(fabs(x) < eps) return 0;  
    else return x < 0 ? -1 : 1;  
}
bool isok(Point a, Point b)
{
    Point x = a - b;
    if(dcmp(x.x) == 0 && dcmp(x.y) == 0) return 0;
    for(int i = 0;i < n;i ++) 
        if(dcmp((a - L[i].S) ^ (b - L[i].S)) * dcmp((a - L[i].E) ^ (b - L[i].E)) > 0) return 0;
    return 1;
}
int main()
{
    freopen("in.txt", "r", stdin);
    int T;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%d", &n);
        for(int i = 0;i < n;i ++) {
            scanf("%lf %lf %lf %lf", &L[i].S.x, &L[i].S.y, &L[i].E.x, &L[i].E.y);
        }
        if(n == 1) {
            puts("Yes!");
            continue;
        }
        bool ok = 0;
        for(int i = 0;i < n;i ++) {
            for(int j = i + 1;j < n;j ++) {
                if(isok(L[i].S, L[j].S)
                    || isok(L[i].S, L[j].E)
                    || isok(L[i].E, L[j].S)
                    || isok(L[i].E, L[j].E)) {
                    ok = 1;
                    break;
                }
            }
            if(ok) break;
        }
        puts(ok ? "Yes!": "No!");
    }
    return 0;
}

POJ 1269 Intersecting Lines
题意:

判断两条直线的位置关系,如果相交,输出交点!
主要是贴个模板。

代码:
#include <cstdio>
#include <algorithm>
#include <cmath>
#define S first
#define E second
#define eps 1e-8
using namespace std;
const int N = 1e2 + 10;
typedef double TP;
struct Point
{
    TP x, y;
    Point(TP x = 0, TP y = 0) :x(x), y(y){}
    Point operator - (const Point& p)
    {
        return Point(x - p.x, y - p.y);
    }
    TP operator ^ (const Point& p)
    {
        return (x * p.y - y * p.x);
    }
};
struct Line
{
    Point S, E;
    Line(Point _s = Point(), Point _e = Point()): S(_s), E(_e) {}
};
int dcmp(double x)
{  
    if(fabs(x) < eps) return 0;  
    else return x < 0 ? -1 : 1;  
}
TP cross(Point& S, Point& E, Point& O)
{
    return (S - O) ^ (E - O);
}
TP cross2(Point& S, Point& E, Point& A, Point& B)
{
    return (E.x - S.x) * (B.y - A.y) - (B.x - A.x) * (E.y - S.y);
}
bool onLine(Line& a, Line& b)
{
    return dcmp(cross(a.S, a.E, b.S)) == 0 && dcmp(cross(a.S, a.E, b.E)) == 0;
}
bool parallel(Line& a, Line& b)
{
    return dcmp(cross2(a.S, a.E, b.S, b.E)) == 0;
}
void intersectionPoint(Line a, Line b, Point& ans)
{
    TP a1, b1, c1, a2, b2, c2;
    a1 = a.S.y - a.E.y;
    b1 = a.E.x - a.S.x;
    c1 = a.S.x * a.E.y - a.S.y * a.E.x;
    a2 = b.S.y - b.E.y;
    b2 = b.E.x - b.S.x;
    c2 = b.S.x * b.E.y - b.S.y * b.E.x;
    ans.x = (c1 * b2 - c2 * b1) / (a2 * b1 - a1 * b2);
    ans.y = (a2 * c1 - a1 * c2) / (a1 * b2 - a2 * b1);
}
int main()
{
    //freopen("in.txt", "r", stdin);
    puts("INTERSECTING LINES OUTPUT");
    int T;
    scanf("%d", &T);
    while(T --)
    {
        Line a, b;
        scanf("%lf %lf %lf %lf", &a.S.x, &a.S.y, &a.E.x, &a.E.y);        
        scanf("%lf %lf %lf %lf", &b.S.x, &b.S.y, &b.E.x, &b.E.y);
        if(onLine(a, b)) puts("LINE");
        else if(parallel(a, b)) puts("NONE");
        else {
            Point ans;
            intersectionPoint(a, b, ans);
            printf("POINT %.2f %.2f\n", ans.x, ans.y);
        }
    }
    puts("END OF OUTPUT");
    return 0;
}

POJ 1556 The Doors

暴力得到所有点之间的距离,然后跑个最短路,数据小,随便搞!


POJ 2653 Pick-up sticks

用一个set去维护还没有被盖住的线段的编号!每次遇到一个新的线段,扫一遍set就好了!


POJ 1066 Treasure Hunt

跟前面的一个题POJ 3304 的思路类似,枚举所有在边界上的点,与终点连一条线,然后看这条线与所有线段的交点,取个最小值!(另:这题数据貌似很水啊!)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值