HDU 4643 GSM

题意: 求一条线段上的点到其他m个点有多少个最短距离, m个点中没有两点到线段上的端点距离相等~
分析:用一个点和其他点的中垂线所在的半平面划分该点所在的区域, 该区域内任意一个点的距离到该点相对其他点距离最近.
具体实现:用一个足够大的矩形覆盖所有点, 然后划分区域, 最后判断所问线段和多少个区域(凸包)有交点~

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>

#define FOR(i, n) for(int i = 0; i < n; i++)
#define MEM(array) memset(array, 0, sizeof(array))
#define eps 1e-7
#define INF (int)1e5
#define PI acos(-1.0)
#define MAX 111
using namespace std;
inline int sgn(const double &x){return x > eps ? 1 : (x < -eps ? -1 : 0);}
inline double sqr(const double &x){return x * x;}
struct Point {
    double x, y;
    Point() {}
    Point(const double &xx, const double &yy):x(xx), y(yy) {}
    friend Point operator + (const Point &b, const Point &a) {
        return Point(b.x + a.x, b.y + a.y);
    }
    friend Point operator - (const Point &b, const Point &a) {
        return Point(b.x - a.x, b.y - a.y);
    }
    Point operator * (const double &a)const{
        return Point(x * a, y * a);
    }
    Point operator / (const double &a) const{
        return Point(x / a, y / a);
    }
    friend double dot(const Point &a, const Point &b) {
        return a.x *b.x + a.y * b.y;
    }
    friend double det(const Point &a, const Point &b) {
        return a.x * b.y - a.y * b.x;
    }
    double len( )const {
        return sqrt(dot(*this, *this));
    }
    bool operator < (const Point &a)const {
        return sgn(x - a.x) < 0 || (sgn(x - a.x) == 0 && sgn(y - a.y) > 0);
    }
    bool operator == (const Point &a)const {
        return sgn(x - a.x ) == 0 && sgn(y - a.y) == 0;
    }
    Point rotate(const double &angle)const{
        double x1 = x * cos(angle) - y * sin(angle);
        double y1 = x * sin(angle) + y * cos(angle);
        return Point(x1, y1);
    }
    void in() {
        scanf("%lf %lf", &x, &y);
    }
    void out()const {
        printf("%.4f    %.4f\n", x, y);
    }
}c[MAX], b[MAX];
int n, m;
struct Line{
    Point s, t;
    Line(){}
    Line(const Point &ss, const Point &tt):s(ss), t(tt){}
    //获取s t的中垂线的s所在的半平面线(左边)
    friend void getPlaneLine(const Line &line, Line &res){
        Point mid  = (line.s + line.t)/ 2;
        Point fa = line.dir().rotate(PI / 2);
        res = Line(mid, mid + fa);
    }
    //线段和直线
    friend bool lineInsectLinevEx(const Line &l1, const Line &lv, Point &res){
            int res1 = sgn( det(l1.s - lv.s, lv.t - lv.s) );
            int res2 = sgn( det(l1.t - lv.s, lv.t - lv.s) );
            if(res1 * res2 < 0){
                double s1 = det(l1.s - lv.s, lv.dir()), s2 = det(l1.t - lv.s, lv.dir());
                res =  (l1.t * s1 - l1.s * s2 ) /(s1 - s2);
                return 1;
            }
            return 0;
    }
    //线段和线段, 不包含端点
    friend bool lineInsectLineEx(const Line &l1, const Line &l2){
        int res1 = sgn( det(l1.s - l2.s, l2.t - l2.s) * det( l1.t - l2.s, l2.t - l2.s) ) ;
        int res2 = sgn( det(l2.s - l1.s, l1.t - l1.s) * det( l2.t - l1.s, l1.t - l1.s) ) ;
        return res1 < 0 && res2 < 0;
    }
    Point dir()const{
        return t - s;
    }
    void out()const{
        s.out();
        t.out();
    }
};
struct Poly{
    vector<Point> p;
    friend Poly getCut(const Poly &poly, const Line &line){
        int tn = poly.p.size();
        Poly resp;
        for(int i = 0; i < tn; i++){
            Point va = poly.p[i] - line.s, vb = line.dir();
            int res = sgn(det(va, vb));
            if(res <= 0){//in half
                resp.p.push_back(poly.p[i]);
            }else {
                int j = i  - 1, k  = i + 1;
                if(j < 0)j = tn - 1;
                if(k > tn - 1)k = 0;
                int id[] = {j, k};
                FOR(kk, 2){
                    va = poly.p[id[kk]] - line.s;
                    res = sgn(det(va, vb) );
                    Point ins;
                    Line l1(poly.p[i], poly.p[id[kk]]);
                    if(res < 0 && lineInsectLinevEx( l1, line, ins)){
                        resp.p.push_back(ins);
                    }
                }
            }
        }
        return resp;
    }
    //和线段的是否有交,不包含端点
    bool isInsectLineEx(const Line &l1){
        if(isContain(l1.s) == true || isContain(l1.t) == true)return true;
        int tn = p.size();
        for(int i = 0; i < tn; i++){
            Line lv(p[i], p[(i + 1)%tn]);
            if(lineInsectLineEx(lv, l1))return true;
        }
        return false;
    }
    bool isContain(const Point &t){
        int sign = 0;
        int tn = p.size();
        for(int i = 0; i < tn; i++){
            int signt = sgn( det( p[i] - t, p[(i + 1)%tn] - t) );
            if(signt){
                if(sign){
                    if(sign != signt )return 0;
                }else {
                    sign = signt;
                }
            }else
                return  0;
        }
        return 1;
    }
}poly[MAX], rect;
void init(){
    FOR(i, n){
        c[i].in();
    }
    FOR(j, m){
        b[j].in();
    }
}

void getPoly(){
    FOR(i, m){
        Poly cur = rect;
        FOR(j, m){
              if(j == i)continue;
              Line line(b[i], b[j]), res;
              getPlaneLine(line, res);
//              res.out();
              cur = getCut(cur, res);
        }
        poly[i] = cur;
    }
}
bool v[MAX];
int judge(int a, int b){
    int ans = 0;

    memset(v, 0, sizeof(v));
//    for(int i = a;  i < b; i++)太二不能多说
    {
        for(int j = 0; j < m; j++){
            if(poly[j].isInsectLineEx(Line(c[a], c[b]))){
                v[j] = 1;
            }
        }
    }
    for(int i  = 0; i < m; i++){
        if(v[i])ans ++, v[i] = 0;
    }
    return ans - 1;
}
void solve(){
    int k ,a, b;
    cin>>k;
    while(k--){
        cin>>a>>b;
        cout<<judge(a - 1, b - 1)<<endl;
    }
}
int main()
{
    rect.p.push_back(Point(-INF, -INF));
    rect.p.push_back(Point(INF, -INF));
    rect.p.push_back(Point(INF, INF));
    rect.p.push_back(Point(-INF, INF));
    while(cin>>n>>m){
        init();
        getPoly();
        solve();
    }
    return 0;
}
/*
*/


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值