【计几】半平面交题集


Acwing - 2803. 凸多边形【求半平面交面积】【有界】

模板题

AC代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#include<algorithm>
using namespace std;

typedef long long LL;
const int N=1100;
const double eps = 1e-9;
const double inf = 1e18;

int dcmp(double x, double y){
    if(fabs(x - y) < eps) return 0;
    if(x < y) return -1;
    return 1;
}
int sign(double x){
    if(fabs(x) < eps) return 0;
    if(x < 0) return -1;
    return 1;
}

struct point{
    double x, y;
    bool operator == (const point a) const {
        return !dcmp(x, a.x) && !dcmp(y, a.y);
    }
};
point operator + (point a, point b) { return {a.x + b.x, a.y + b.y}; }
point operator - (point a, point b) { return {a.x - b.x, a.y - b.y}; }
point operator * (point a, double b) { return {a.x * b, a.y * b}; }
point operator / (point a, double b) { return {a.x / b, a.y / b}; }

double length(point a) { return sqrt(a.x * a.x + a.y * a.y); }
double cross(point a, point b) { return a.x * b.y - a.y * b.x; }
double dot(point a, point b) { return a.x * b.x + a.y * b.y; }
double area(point a, point b, point c) { return cross(b - a, c - a); }
double project(point a, point b, point c) { return dot(b - a, c - a) / length(b - a); }
double angle(point a) { return atan2(a.y, a.x); }


struct line{
    point p, v;
    bool operator < (const line a) const{
        double A = angle(v), B = angle(a.v);
        if(dcmp(A, B)) return dcmp(A, B) < 0;
        return cross(a.v, p - a.p) > 0;
    }
};

point get_line_intersection(point p, point v, point q, point w){
    if(sign(cross(v, w)) == 0) return {inf, inf};
    point u = p - q;
    double t = cross(w, u) / cross(v, w);
    return p + v * t;
}
point get_line_intersection(line a, line b){
    return get_line_intersection(a.p, a.v, b.p, b.v);
}
bool on_right(line a, line b, line c){
    point inter = get_line_intersection(b, c);
    if(inter == (point){inf, inf}) return 0;
    return cross(a.v, inter - a.p) <= 0;
}

point P[N];
line L[N];
int cnt;
int q[N];
point inter[N];

double half_plane_intersection()
{
    sort(L, L + cnt);
    int hh = 0, tt = -1;
    for(int i=0; i<cnt; i++)
    {
        if(i && dcmp(angle(L[i].v), angle(L[i - 1].v)) == 0) continue;
        while(hh < tt && on_right(L[i], L[q[tt - 1]], L[q[tt]])) tt--;
        while(hh < tt && on_right(L[i], L[q[hh]], L[q[hh + 1]])) hh++;
        q[++tt] = i;
    }
    while(hh < tt && on_right(L[q[hh]], L[q[tt - 1]], L[q[tt]])) tt--;
    q[++tt] = q[hh];

    int k = 0;
    for(int i=hh; i<tt; i++)
        inter[k++] = get_line_intersection(L[q[i]], L[q[i + 1]]);
    
    double res = 0;

    for(int i=0; i<k; i++) res += area({0, 0}, inter[i], inter[(i + 1) % k]);

    return fabs(res) / 2;
}


int main()
{
    int T; scanf("%d", &T);
    while(T--)
    {
        int n; scanf("%d", &n);
        for(int i=0; i<n; i++) scanf("%lf %lf", &P[i].x, &P[i].y);
        
        for(int i=0; i<n; i++) L[cnt++] = {P[i], P[(i + 1) % n]  - P[i]};
    }

    double ans = half_plane_intersection();

    printf("%.3f", ans);

    system("pause");
    return 0;
}

Acwing - 2957. 赛车【无界且没有相向直线】

题意:看题。

注意:这道题无界且没有相向直线,不用加边界框。

  • 小tips:

半平面交处理出来的边集是没有向量方向相等的,每个极角都不相等。而这道题有的直线会重合,题目又要求不能舍去重合的,直接用板子会出问题。因此把相等的放在一起当成一个来考虑。这里储存数据的方式很值得学习。

struct line{
    point p, v;
    vector<int>vec;
};
map<pair<int, int>, vector<int> >mp;

for(int i=1; i<= n; i++) mp[{k[i], v[i]}].push_back(i);
for(auto it : mp)
    L[cnt++] = {{0, (double)it.first.first}, {1, (double)it.first.second}, it.second};

代码(过10/总11数据):

#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;

typedef double long_double;
typedef long long LL;
const int N=1e5 + 10;
const double eps = 1e-18;
const double inf = 1e18;
const double pi = acos(-1);

int dcmp(double x, double y){
    if(fabs(x - y) < eps) return 0;
    if(x < y) return -1;
    return 1;
}
int sign(double x){
    if(fabs(x) < eps) return 0;
    if(x < 0) return -1;
    return 1;
}

struct point{
    double x, y;
    bool operator == (const point a) const {
        return !dcmp(x, a.x) && !dcmp(y, a.y);
    }
};
point operator + (point a, point b) { return {a.x + b.x, a.y + b.y}; }
point operator - (point a, point b) { return {a.x - b.x, a.y - b.y}; }
point operator * (point a, double b) { return {a.x * b, a.y * b}; }
point operator / (point a, double b) { return {a.x / b, a.y / b}; }

double length(point a) { return sqrt(a.x * a.x + a.y * a.y); }
double cross(point a, point b) { return a.x * b.y - a.y * b.x; }
double dot(point a, point b) { return a.x * b.x + a.y * b.y; }
double area(point a, point b, point c) { return cross(b - a, c - a); }
double project(point a, point b, point c) { return dot(b - a, c - a) / length(b - a); }
double angle(point a) { return atan2(a.y, a.x); }

vector<int> operator + (vector<int>a, vector<int>b){
    for(auto it:b) a.push_back(it);
    return a;
}


struct line{
    point p, v;
    vector<int>vec;
    bool operator < (const line a) const {
        double A = angle(v), B = angle(a.v);
        if(dcmp(A, B)) return dcmp(A, B) < 0;
        return cross(a.v, p - a.p) > 0;
    }
};

point get_line_intersection(point p, point v, point q, point w){
    point u = p - q;
    double t = cross(w, u) / cross(v, w);
    return p + v * t;
}
point get_line_intersection(line a, line b){
    return get_line_intersection(a.p, a.v, b.p, b.v);
}
bool on_right(line a, line b, line c){
    point inter = get_line_intersection(b, c);
    return sign(cross(a.v, inter - a.p)) < 0;
}

line L[N];
int cnt;
int q[N];
vector<int>ans;

void half_plane_intersection()
{
    sort(L, L + cnt);
    int hh = 0, tt = -1;
    for(int i=0; i<cnt; i++)
    {
        if(i && dcmp(angle(L[i].v), angle(L[i - 1].v)) == 0) continue;
        while(hh < tt && on_right(L[i], L[q[tt - 1]], L[q[tt]])) tt--;
        while(hh < tt && on_right(L[i], L[q[hh]], L[q[hh + 1]])) hh++;
        q[++tt] = i;
    }
    while(hh < tt && on_right(L[q[hh]], L[q[tt - 1]], L[q[tt]])) tt--;
    
    for(int i=hh; i<= tt; i++) ans = ans + L[q[i]].vec;
    sort(ans.begin(), ans.end(), less<int>());
}

int k[N], v[N];
map<pair<int, int>, vector<int> >mp;

int main()
{
    int n; scanf("%d", &n);
    L[0] = {{0, 0}, {0, -1}};
    L[1] = {{0, 0}, {1, 0}};
    cnt = 2;

    for(int i=1; i<= n; i++) scanf("%d", &k[i]);
    for(int i=1; i<= n; i++) scanf("%d", &v[i]);
    for(int i=1; i<= n; i++) mp[{k[i], v[i]}].push_back(i);

    for(auto it : mp)
        L[cnt++] = {{0, (double)it.first.first}, {1, (double)it.first.second}, it.second};

    half_plane_intersection();

    printf("%d\n", ans.size());

    for(auto it : ans)
        printf("%d ", it);


    system("pause");
    return 0;
}

poj 3525 - Most Distant Point from the Sea【半平面交 + 二分】

题意:给定一个凸多边形,求凸多边形内某点到各边的最小距离的最大值。

思路:二分答案,判断是否有解即可。

AC代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;

typedef double long_double;
typedef long long LL;
const int N=110;
const double eps = 1e-9;
const double pi = acos(-1);

int dcmp(double x, double y){
    if(fabs(x - y) < eps) return 0;
    if(x < y) return -1;
    return 1;
}
int sign(double x){
    if(fabs(x) < eps) return 0;
    if(x < 0) return -1;
    return 1;
}

struct point{
    double x, y;
    bool operator == (const point a) const {
        return !dcmp(x, a.x) && !dcmp(y, a.y);
    }
};
point operator + (point a, point b) { return {a.x + b.x, a.y + b.y}; }
point operator - (point a, point b) { return {a.x - b.x, a.y - b.y}; }
point operator * (point a, double b) { return {a.x * b, a.y * b}; }
point operator / (point a, double b) { return {a.x / b, a.y / b}; }

double length(point a) { return sqrt(a.x * a.x + a.y * a.y); }
double cross(point a, point b) { return a.x * b.y - a.y * b.x; }
double dot(point a, point b) { return a.x * b.x + a.y * b.y; }
double area(point a, point b, point c) { return cross(b - a, c - a); }
double project(point a, point b, point c) { return dot(b - a, c - a) / length(b - a); }
double angle(point a) { return atan2(a.y, a.x); }
point rotate(point a, double rad) { return {a.x * cos(rad) - a.y * sin(rad), a.x * sin(rad) + a.y * cos(rad)}; }
point norm(point a) { return a / length(a); }


struct line{
    point p, v;
    bool operator < (const line a) const {
        double A = angle(v), B = angle(a.v);
        if(dcmp(A, B)) return dcmp(A, B) < 0;
        return cross(a.v, p - a.p) > 0;
    }
};

point get_line_intersection(point p, point v, point q, point w){
    point u = p - q;
    double t = cross(w, u) / cross(v, w);
    return p + v * t;
}
point get_line_intersection(line a, line b){
    return get_line_intersection(a.p, a.v, b.p, b.v);
}
bool on_right(line a, line b, line c){
    point inter = get_line_intersection(b, c);
    return cross(a.v, inter - a.p) <= 0;
}


line L[N];
int cnt;
int q[N];
point P[N];


bool check()
{
    sort(L, L + cnt);
    int hh = 0, tt = -1;
    for(int i=0; i<cnt; i++)
    {
        if(i && dcmp(angle(L[i].v), angle(L[i - 1].v)) == 0) continue;
        while(hh < tt && on_right(L[i], L[q[tt - 1]], L[q[tt]])) tt--;
        while(hh < tt && on_right(L[i], L[q[hh]], L[q[hh + 1]])) hh++;
        q[++tt] = i;
    }
    while(hh < tt && on_right(L[q[hh]], L[q[tt - 1]], L[q[tt]])) tt--;

    return tt - hh + 1 >= 3;
}




int main()
{
    int n;
    while(scanf("%d", &n) != EOF)
    {
        if(n == 0) break;
        for(int i=0; i<n; i++) scanf("%lf %lf", &P[i].x, &P[i].y);
        double le = 0, ri = 10000;
        while(ri - le > eps)
        {
            double mid = (le + ri) / 2;
            cnt = 0;
            for(int i=0; i<n; i++) L[cnt++] = {P[i] + norm(rotate(P[(i + 1) % n] - P[i], pi / 2)) * mid, P[(i + 1) % n] - P[i]};
            if(check()) le = mid;
            else ri = mid;
        }
        printf("%.6f\n", ri);
    }


    system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值