HDU 3982 (半平呈送 多边形和圆面积交)
HDU 3982 (半平面交 多边形和圆面积交)
题目链接:点击这里
题意:一块圆形蛋糕, 上面有一个点是樱桃, 然后切n刀, 求樱桃所在的那一块面积占总面积的百分比。
n刀每次取樱桃所在的半平面, 然后最外面加一个大矩形限制半平面交,最后求出的半平面交和圆面积并一下就是樱桃那块的面积了。
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
#define maxn 100005
const double eps = 1e-8;
const double INF = 1e20;
const double pi = acos (-1.0);
int dcmp (double x) {
if (fabs (x) < eps) return 0;
return (x < 0 ? -1 : 1);
}
inline double sqr (double x) {return x*x;}
//*************点
struct Point {
double x, y;
Point (double _x = 0, double _y = 0):x(_x), y(_y) {}
void input () {scanf ("%lf%lf", &x, &y);}
void output () {printf ("%.2f %.2f\n", x, y);}
bool operator == (const Point &b) const {
return (dcmp (x-b.x) == 0 && dcmp (y-b.y) == 0);
}
bool operator < (const Point &b) const {
return (dcmp (x-b.x) == 0 ? dcmp (y-b.y) < 0 : x < b.x);
}
Point operator + (const Point &b) const {
return Point (x+b.x, y+b.y);
}
Point operator - (const Point &b) const {
return Point (x-b.x, y-b.y);
}
Point operator * (double a) {
return Point (x*a, y*a);
}
Point operator / (double a) {
return Point (x/a, y/a);
}
double len2 () {//返回长度的平方
return sqr (x) + sqr (y);
}
double len () {//返回长度
return sqrt (len2 ());
}
Point change_len (double r) {//转化为长度为r的向量
double l = len ();
if (dcmp (l) == 0) return *this;//零向量返回自身
r /= l;
return Point (x*r, y*r);
}
Point rotate_left () {//顺时针旋转90度
return Point (-y, x);
}
Point rotate_right () {//逆时针旋转90度
return Point (y, -x);
}
Point rotate (Point p, double ang) {//绕点p逆时针旋转ang
Point v = (*this)-p;
double c = cos (ang), s = sin (ang);
return Point (p.x + v.x*c - v.y*s, p.y + v.x*s + v.y*c);
}
Point normal () {//单位法向量
double l = len ();
return Point (-y/l, x/l);
}
};
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 dis (Point a, Point b) {//两个点的距离
Point p = b-a; return p.len ();
}
double rad_degree (double rad) {//弧度转化为角度
return rad/pi*180;
}
double rad (Point a, Point b) {//两个向量的夹角
return fabs (atan2 (fabs (cross (a, b)), dot (a, b)) );
}
bool parallel (Point a, Point b) {//向量平行
double p = rad (a, b);
return dcmp (p) == 0 || dcmp (p-pi) == 0;
}
//************直线 线段
struct Line {
Point s, e;//直线的两个点
double k;//极角
Line () {}
Line (Point _s, Point _e) {
s = _s, e = _e;
k = atan2 (e.y - s.y,e.x - s.x);
}
//ax+by+c = 0
Line (double a, double b, double c) {
if (dcmp (a) == 0) {
s = Point (0, -c/b);
e = Point (1, -c/b);
}
else if (dcmp (b) == 0) {
s = Point (-c/a, 0);
e = Point (-c/a, 1);
}
else {
s = Point (0, -c/b);
e = Point (1, (-c-a)/b);
}
get_angle ();
}
//一个点和倾斜角确定直线
Line (Point p, double ang) {
k = ang;
s = p;
if (dcmp (ang-pi/2) == 0) {
e = s + Point (0, 1);
}
else
e = s + Point (1, tan (ang));
}
void input () {
s.input ();
e.input ();
}
void adjust () {
if (e < s) swap (e, s);
}
double length () {//求线段长度
return dis (s, e);
}
void get_angle () {
k = atan2 (e.y - s.y,e.x - s.x);
}
double angle () {//直线的倾斜角
if (dcmp (k) < 0) k += pi;
if (dcmp (k-pi) == 0) k -= pi;
return k;
}
Point operator &(const Line &b)const {//直线的交点(保证存在)
Point res = s;
double t = (cross (s - b.s, b.s - b.e))/cross (s - e, b.s - b.e);
res.x += (e.x - s.x)*t;
res.y += (e.y - s.y)*t;
return res;
}
};
int relation (Point p, Line l) {//点和直线的关系
//1:在左侧 2:在右侧 3:在直线上
int c = dcmp (cross (p-l.s, l.e-l.s));
if (c < 0) return 1;
else if (c > 0) return 2;
else return 3;
}
double point_to_line (Point p, Line a) {//点到直线的距离
return fabs (cross (p-a.s, a.e-a.s) / a.length ());
}
Point projection (Point p, Line a) {//点在直线上的投影
return a.s + (((a.e-a.s) * dot (a.e-a.s, p-a.s)) / (a.e-a.s).len2() );
}
//***************圆
struct Circle {
//圆心 半径
Point p;
double r;
Circle () {}
Circle (Point _p, double _r) : p(_p), r(_r) {}
Circle (double a, double b, double _r) {
p = Point (a, b);
r = _r;
}
void input () {
p.input ();
scanf ("%lf", &r);
}
void output () {
p.output ();
printf (" %.2f\n", r);
}
bool operator == (const Circle &a) const {
return p == a.p && (dcmp (r-a.r) == 0);
}
double area () {//面积
return pi*r*r;
}
double circumference () {//周长
return 2*pi*r;
}
bool operator < (const Circle &a) const {
return p < a.p || (p == a.p && r < a.r);
}
};
int relation (Point p, Circle a) {//点和圆的关系
//0:圆外 1:圆上 2:圆内
double d = dis (p, a.p);
if (dcmp (d-a.r) == 0) return 1;
return (dcmp (d-a.r) < 0 ? 2 : 0);
}
int relation (Line a, Circle b) {//直线和圆的关系
//0:相离 1:相切 2:相交
double p = point_to_line (b.p, a);
if (dcmp (p-b.r) == 0) return 1;
return (dcmp (p-b.r) < 0 ? 2 : 0);
}
int line_cirlce_intersection (Line v, Circle u, Point &p1, Point &p2) {//直线和圆的交点
//返回交点个数 交点保存在引用中
if (!relation (v, u)) return 0;
Point a = projection (u.p, v);
double d = point_to_line (u.p, v);
d = sqrt (u.r*u.r - d*d);
if (dcmp (d) == 0) {
p1 = a, p2 = a;
return 1;
}
p1 = a + (v.e-v.s).change_len (d);
p2 = a - (v.e-v.s).change_len (d);
return 2;
}
double circle_traingle_area (Point a, Point b, Circle c) {//圆心三角形的面积
//a.output (), b.output (), c.output ();
Point p = c.p; double r = c.r; //cout << cross (p-a, p-b) << endl;
if (dcmp (cross (p-a, p-b)) == 0) return 0;
Point q[5];
int len = 0;
q[len++] = a;
Line l(a, b);
Point p1, p2;
if (line_cirlce_intersection (l, c, q[1], q[2]) == 2) {
if (dcmp (dot (a-q[1], b-q[1])) < 0) q[len++] = q[1];
if (dcmp (dot (a-q[2], b-q[2])) < 0) q[len++] = q[2];
}
q[len++] = b;
if (len == 4 && dcmp (dot (q[0]-q[1], q[2]-q[1])) > 0)
swap (q[1], q[2]);
double res = 0;
for (int i = 0; i < len-1; i++) {
if (relation (q[i], c) == 0 || relation (q[i+1], c) == 0) {
double arg = rad (q[i]-p, q[i+1]-p);
res += r*r*arg/2.0;
}
else {
res += fabs (cross (q[i]-p, q[i+1]-p))/2;
}
} //cout << res << ".." << endl;
return res;
}
double area_polygon_circle (Circle c, Point *p, int n) {//多边形和圆交面积
double ans = 0;
for (int i = 0; i < n; i++) {
int j = (i+1)%n;
if (dcmp (cross (p[j]-c.p, p[i]-c.p)) >= 0)
ans += circle_traingle_area (p[i], p[j], c);
else
ans -= circle_traingle_area (p[i], p[j], c);
}
return fabs (ans);
}
//半平面交,直线的左边代表有效区域
bool HPIcmp (const Line &a, const Line &b) {
if (fabs(a.k - b.k) > eps)
return a.k < b.k;
return cross (a.s - b.s, b.e - b.s) < 0;
}
Line Q[maxn];
void HPI(Line line[], int n, Point res[], int &resn) {
//半平面数组 半平面个数 半平面交顶点 半平面交顶点个数
for (int i = 0; i < n; i++) line[i].get_angle ();
int tot = n;
sort(line,line+n,HPIcmp);
tot = 1;
for(int i = 1;i < n;i++){
if(fabs(line[i].k - line[i-1].k) > eps)
line[tot++] = line[i];
}
int head = 0, tail = 1;
Q[0] = line[0];
Q[1] = line[1];
resn = 0;
for (int i = 2; i < tot; i++) {
if (fabs(cross (Q[tail].e-Q[tail].s, Q[tail-1].e-Q[tail-1].s)) < eps || fabs(cross (Q[head].e-Q[head].s, Q[head+1].e-Q[head+1].s)) < eps)
return;
while(head < tail && (cross ((Q[tail]&Q[tail-1])-line[i].s, line[i].e-line[i].s)) > eps) tail--;
while(head < tail && (cross ((Q[head]&Q[head+1]) - line[i].s, line[i].e-line[i].s)) > eps)
head++;
Q[++tail] = line[i];
}
while(head < tail && (cross ((Q[tail]&Q[tail-1]) - Q[head].s, Q[head].e-Q[head].s)) > eps)
tail--;
while(head < tail && (cross ((Q[head]&Q[head-1]) -Q[tail].s, Q[tail].e-Q[tail].e)) > eps)
head++;
if(tail <= head + 1)
return;
for(int i = head; i < tail; i++)
res[resn++] = Q[i]&Q[i+1];
if(head < tail - 1)
res[resn++] = Q[head]&Q[tail];
}
double r;
int n, m;
Line l[maxn];
Point O, ans[maxn];
Line hp[maxn];
int main () {
int t, kase = 0;
scanf ("%d", &t);
while (t--) {
scanf ("%lf%d", &r, &n);
for (int i = 0; i < n; i++) {
l[i].input ();
}
O.input ();
int cnt = 0;
hp[cnt++] = Line (Point (r, -r), Point (r, r));
hp[cnt++] = Line (Point (r, r), Point (-r, r));
hp[cnt++] = Line (Point (-r, r), Point (-r, -r));
hp[cnt++] = Line (Point (-r, -r), Point (r, -r));
for (int i = 0; i < n; i++) {
if (relation (O, l[i]) == 1) {
hp[cnt++] = l[i];
}
else
hp[cnt++] = Line (l[i].e, l[i].s);
}
HPI (hp, cnt, ans, m);
Circle C (Point (0, 0), r);
double area = area_polygon_circle (C, ans, m);
double tot = pi*r*r;
area = area * 100 / tot;
printf ("Case %d: %.5f%%\n", ++kase, area);
}
return 0;
}