文章目录
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;
}