像UVA 11177的话是一个圆与多边形相交的特殊情况, 圆心在原点, 原点一定在凸多边形内部,可以用特殊的做法做
而这道题的话就需要这类问题的通用做法
在计算多边形面积的时候,我们任意找一个点,与多边形上任意一条边形成一个三角形,计算N个三角形的有向面积和
在圆与多边形交的情况下,这个点就可以是圆心,求的是N个三角形与圆相交的有向面积。
三角形与圆相交可以分为四种情况。具体可见代码,要注意的地方就是第三种情况的判定条件
/*
1. 平行向量叉积为0的性质 可以用来判断点是否在直线上
2. 点积的符号 可以用来判断点与线段的位置关系 角度等等
3. 叉积的大小可以用于计算距离等等
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <stack>
#include <cctype>
#include <cmath>
#include <vector>
#include <sstream>
#include <bitset>
#include <deque>
#include <iomanip>
using namespace std;
#define pr(x) cout << #x << " = " << x << endl;
#define bug cout << "bugbug" << endl;
#define ppr(x, y) printf("(%d, %d)\n", x, y);
#define pdr(x, y) printf("(%.3f, %.3f)\n", x, y);
#define pfun(a, b) printf("x = %d f(x) = %d\n", a, b);
typedef long long ll;
typedef pair<int, int> P;
const int MOD = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 1e2 + 4;
const int maxm = 1e4 + 4;
inline double add(double a, double b = 0){
return fabs(a + b) < eps * (fabs(a) + fabs(b)) ? 0 : a + b;
}
inline int dcmp(double d){
if (fabs(d) < eps) return 0;
return d > 0 ? 1 : -1;
}
struct Point;
typedef Point Vector;
typedef vector<Point> Polygon;
struct Point{
double x, y;
Point(double _x = 0, double _y = 0):x(_x), y(_y){
}
//Point相减显然可以得到Vector
Vector operator + (const Vector &rhs) const { return Vector(add(x, rhs.x), add(y, rhs.y)); }
Vector operator - (const Vector &rhs) const { return Vector(add(x, -rhs.x), add(y, -rhs.y)); }
Vector operator * (const double &rhs) const { return Vector(rhs * x, rhs * y);}
void operator += (const Vector &rhs) { *this = *this + rhs; }
void operator -= (const Vector &rhs) { *this = *this - rhs; }
void operator *= (const double &rhs) { *this = *this * rhs; }
double dot (const Vector &rhs) const { return add(x * rhs.x, y * rhs.y);}
double det (const Vector &rhs) const { return add(x * rhs.y, -y * rhs.x);}
bool operator < (const Point& rhs) const{
if (!dcmp(x-rhs.x)) return dcmp(y-rhs.y) == -1;
return dcmp(x-rhs.x) == -1;
}
bool operator == (const Point& rhs) const{ return dcmp(x-rhs.x) == 0 && dcmp(y-rhs.y) == 0; }
double length() { return sqrt(dot(*this));}
//逆时针旋转
Vector rotate(double rad) { return Vector(add(x * cos(rad), -y * sin(rad)), add(x * sin(rad), y * cos(rad))); }
void print() { pdr(x, y); }
void read(){
scanf("%lf%lf", &x, &y);
}
};
const Point O = Point{0, 0};
Vector MakeVector(double angle, double len){
// MakeVector(angle, len) 的反向向量是 MakeVector(angle+pi, len) 或者 MakeVector(angle, -len)
return Point{add(cos(angle) * len), add(sin(angle) * len)};
}
bool on_seg(Point s, Point t, Point p){
return dcmp((s-p).det(t-p)) == 0 && dcmp((s-p).dot(t-p)) <= 0;
//此处有没有等于 就是含不含端点
}
//求直线的交点
Point intersection(Point p1, Point p2, Point q1, Point q2){//p1p2 与 q1q2不能是平行的
return p1 + (p2 - p1) * ((q2 - q1).det(q1 - p1) / (q2 - q1).det(p2 - p1));
}
double dis_point_line(Point P, Point A, Point B){
// 注意参数的顺序, 利用的是叉积
return fabs((A-P).det(B-P) / (A-B).length());
}
double dis_point_seg(Point P, Point A, Point B){
Vector v1 = P - A, v2 = B - A, v3 = P - B;
if (dcmp(v1.dot(v2)) == -1) return v1.length();
else if (dcmp(v3.dot(v2)) == 1) return v3.length();
else return dis_point_line(P, A, B);
}
double Area(Polygon& Pnt, int n){
double area = 0;
for (int i = 1; i < n - 1; ++i)
area += (Pnt[i] - Pnt[0]).det(Pnt[i+1] - Pnt[0]);
return area * 0.5;
}
struct Line{
/*
Line = p + tv; p是直线上一个点, v是直线的方向向量
*/
Point p;
Vector v;
Line(Point A = O, Point B = O):p(A), v(B-A){
}//这里方向向量 B-A 和 A-B 会影响到getpoint
Point getpoint(double t) const{return p + v*t;}
};
struct Circle{
Point c;
double r;
Circle(Point _c = O, double _r = 0):c(_c), r(_r){
}
Point getpoint(double a){
return Point(c.x + cos(a) * r, c.y + sin(a) * r);
}
double area(double ang){
return 0.5 * r * r * ang;
}
};
int intersection_line_circle(Line L, Circle C, double& t1, double& t2, vector<Point>& sol){
/*
计算直线与圆的交点
返回值为交点数量
sol存储交点
*/
double a = L.v.x, b = L.p.x - C.c.x, c = L.v.y, d = L.p.y - C.c.y;
double e = a*a + c*c, f = 2 * (a*b + c*d), g = b*b + d*d - C.r*C.r;
double delta = f*f - 4*e*g;
if (dcmp(delta) < 0) return 0; //相离
if (dcmp(delta) == 0){
t1 = t2 = -f / 2 / e;
sol.push_back(L.getpoint(t1));
return 1;
}
t1 = (-f + sqrt(delta)) / (2*e); sol.push_back(L.getpoint(t1));
t2 = (-f - sqrt(delta)) / (2*e); sol.push_back(L.getpoint(t2));
return 2;
}
int in_polygon(Point P, Polygon& poly){
/*
判断点是否在多边形内 (可以是凹多边形, 可以自交的多边形)
返回值为-1表示点在多边形的边上, 1表示在多边形内部, 0表示在多边形的外部
poly内的点可以是逆时针排序的
如果多边形是凸多边形的话, 可以简化为判断点是不是在所有边的左边(要求逆时针)
*/
int wn = 0; // winding number
int n = poly.size();
for (int i = 0; i < n; ++i){
if (on_seg(P, poly[i], poly[(i+1) % n])) return -1;
int k = dcmp((poly[(i+1) % n] - poly[i]).det(P - poly[i]));
int d1 = dcmp(poly[i].y - P.y);
int d2 = dcmp(poly[(i+1)%n].y - P.y);
if (k > 0 && d1 <= 0 && d2 > 0) wn++;//注意此处的 = 取不取的到
if (k < 0 && d2 <= 0 && d1 > 0) wn--;
}
if (wn) return 1;
return 0;
}
bool in_circle(Point P, Circle C){
double d = (P-C.c).length();
return dcmp(d-C.r) < 0;
}
inline double angle(Vector v) {
/*
返回向量的极角
与圆相关的题中会大量用到
返回值为(-pi, pi]
*/
double ret = add(atan2(v.y, v.x), 0);
if (dcmp(ret < 0)) ret += 2 * pi;
return ret;
}
bool cmp(Point A, Point B){
return angle(A) < angle(B);
}
Point Origin;
int n;
Polygon Pnt;
double limit;
double Area(Point A, Point B, Point C){
vector<Point> Pnt;
Pnt.push_back(A);
Pnt.push_back(B);
Pnt.push_back(C);
return fabs(Area(Pnt, 3));
}
double angle(Vector A, Vector B){
return acos(A.dot(B) / A.length() / B.length());
}
double Compute(Circle C, Point a, Point b){
if (dcmp((C.c - a).det(a-b)) == 0) return 0;
int sig = dcmp((a-C.c).det(b-C.c));
double da = (a-C.c).length(), db = (b-C.c).length();
// cout << da << ' ' << db << endl;
if (da > db){
swap(da, db);
swap(a, b);
}
double t1, t2;
vector<Point> sol;
int cnt = intersection_line_circle(Line(a, b), C, t1, t2, sol), k = 0;
if (cnt == 2 && (sol[0]-b).length() > (sol[1]-b).length()) k = 1;
if (dcmp(da - C.r) <= 0){
if (dcmp(db - C.r) <= 0) return sig * Area(C.c, a, b);
double ret = Area(C.c, a, sol[k]) + C.area(angle(sol[k]-C.c, b-C.c));
return ret * sig;
}
double dis = dis_point_seg(C.c, a, b);
if (dcmp(dis - C.r) >= 0) return sig * C.area(angle(a-C.c, b-C.c));
double k1 = C.r / (C.c - b).length(), k2 = C.r / (C.c - a).length();
Point c = C.c + (a-C.c) * k2, d = C.c + (b-C.c) * k1;
double ret = C.area(angle(c-C.c, d-C.c)) - (C.area(angle(sol[0]-C.c, sol[1]-C.c)) - Area(C.c, sol[0], sol[1]));
return ret * sig;
}
double Compute(double r){
if (dcmp(r) == 0) return 0;
double ret = 0;
for (int i = 0; i < n; ++i){
ret += Compute(Circle(Origin, r), Pnt[i], Pnt[(i+1) % n]);
}
return ret;
}
int main(){
//必须编译过才能交
// ios::sync_with_stdio(false);
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
//
int ik = 1, i, j, k, kase;
scanf("%d", &kase);
while(kase--){
scanf("%d", &n);
Pnt.resize(n);
for (i = 0 ; i < n; ++i) Pnt[i].read();
Origin.read();
scanf("%lf", &limit);
limit = limit / 100 * Area(Pnt, n);
double lft = 0, rght = 10000;
while(lft + eps < rght){
double mid = (lft + rght) / 2;
double area = Compute(mid);
// cout << mid << ' ' << area << endl;
if (dcmp(area - limit) >= 0) rght = mid;
else lft = mid;
}
printf("Case %d: %.0f\n", ik++, lft);
}
return 0;
}
/*
4 3
-1 1
-1 -1
1 -1
1 1
*/