题意:给一个简单多边形,点数不超过5000,再给一个圆心 和 整数P,要求确定圆的半径 r,使得s = 简单多边形面积,s1 = 圆与简单多边形的公共面积,且 s/s1 = P/100. r只要求精确到整数即可。
链接:
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18797 (VJ)
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3129 (UVA)
解法:二分半径,直到找到合适的 r 为止。现在问题变为 如何求 圆和简单多边形的公共面积。这里的简单多边形,题目给了一个很好的定义,如下。( In geometry, a simple polygon is a closed polygonal chain of line segments in the plane which do not have points in common other than the common vertices of pairs of consecutive segments.) 简单多边形可以是凸多边形,也可以是凹多变形
我们这样做,将多边形每条边的两点和圆心连线,这样就得到若干个“中心三角形“,中心三角形与圆的公共面积分4种情况讨论。具体情况这篇博客:http://www.cnblogs.com/lxglbk/archive/2012/08/12/2634192.html 。个人认为这位博主已经讲述地十分到位了。
本题代码
//Hello. I'm Peter.
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
#define peter cout<<"i am peter"<<endl
typedef long long ll;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const double eps = 1e-9, pi = acos(-1.0);
inline int sgn(double x){
if(fabs(x) < eps) return 0;
else return x > 0? 1 : -1;
}
double sq(double x){return x*x;}
struct Point{
double x, y;
Point(){};
Point(double x1, double y1){x = x1, y = y1;}
};
typedef Point Vector;
bool cmpxy(const Point a, const Point b){if(sgn(a.x-b.x)) return a.x < b.x; else return a.y < b.y;}
bool cmpyx(const Point a, const Point b){if(sgn(a.y-b.y)) return a.y < b.y; else return a.x < b.x;}
bool cmpYx(const Point a, const Point b){if(sgn(a.y-b.y)) return a.y > b.y; else return a.x < b.x;}
bool cmpyX(const Point a, const Point b){if(sgn(a.y-b.y)) return a.y < b.y; else return a.x > b.x;}
Vector operator + (const Vector a, const Vector b){return Vector(a.x + b.x, a.y + b.y);}
Vector operator - (const Vector a, const Vector b){return Vector(a.x - b.x, a.y - b.y);}
double operator * (const Vector a, const Vector b){return a.x * b.x + a.y * b.y;}
double operator % (const Vector a, const Vector b){return a.x * b.y - a.y * b.x;}
Vector operator * (const Vector a, const double b){return Vector(a.x * b, a.y * b);}
Vector operator * (const double b, const Vector a){return Vector(a.x * b, a.y * b);}
Vector operator / (const Vector a, const double b){return Vector(a.x / b, a.y / b);}
bool operator == (const Point a, const Point b){return sgn(a.x - b.x)==0 && sgn(a.y - b.y)==0;}
bool operator || (const Vector a, const Vector b){return sgn(a % b)==0;}
bool operator / (const Vector a, const Vector b){return sgn(a % b)!=0;}
double Length(Vector v){return (double)sqrt((double)(v.x * v.x + v.y * v.y));}
double LenSq(Vector v){return v.x*v.x + v.y*v.y;}
double Dis(Point a, Point b){return Length(a - b);}
Vector Rotate(Vector v, double rad){return Vector(v.x * cos(rad) - v.y * sin(rad), v.x * sin(rad) + v.y * cos(rad));}
Vector Norv(Vector v){return Vector(v.y, -v.x);}
Vector Unitv(Vector v){return v / Length(v);}
double angle(Vector v){return atan2(v.y, v.x);}
double angle(Vector a, Vector b){
double ans = angle(a) - angle(b);
while(sgn(ans) < 0) ans += 2*pi; while(sgn(ans) >= 2*pi) ans -= 2*pi;
return fmin(ans, 2*pi - ans);
}
double Area_Tri(Point p1, Point p2, Point p3){return 0.5 * fabs((p2 - p1) % (p3 - p1));}
double Area_Tri(double a, double b, double c){
double p = (a+b+c)/2;
return (double)sqrt((double)(p*(p-a)*(p-b)*(p-c)));
}
double Area_Poly(Point *p, int n){
//求任意简单多边形的无向面积,前提要将p逆时针或顺时针排序
if(n <= 2) return 0;
Point o = Point(0, 0);
p[n++] = p[0];
double ans = 0;
for(int i = 0; i < n-1; i++){
ans += Area_Tri(o, p[i], p[i+1]) * sgn((p[i] - o) % (p[i+1] - o));
}
return fabs(ans);
}
/*--------------------------直线--------------------------*/
struct Line{
Point p; Vector v;
Line(){};
Line(Point p1, Vector v1){p = p1, v = v1;}
};
Point operator / (const Line a, const Line b){
double t = ((b.p - a.p) % b.v) / (a.v % b.v);
return a.p + a.v * t;
}
double Dis(Point p, Line l){return fabs(l.v % (p - l.p)) / Length(l.v);}
double angle(Line a, Line b){double ans = angle(a.v, b.v); return fmin(ans, pi - ans);}
double angle(Line l){
double a = angle(Vector(1, 0), l.v);
if(Rotate(Vector(1, 0), a) / l.v) a = pi - a;
return a;
}
/*--------------------------线段--------------------------*/
struct Seg{
Point p1, p2;
Seg(){};
Seg(Point p11, Point p22){p1 = p11, p2 = p22;}
};
bool PointOnSeg(Point p, Seg s){
if((s.p1 - p) / (s.p2 - p)) return false;
else if(sgn((s.p1 - p) * (s.p2 - p)) > 0) return false;
else return true;
}
bool operator / (const Seg a, const Seg b){//此函数容易写错,且不同题目需要修改,特别注意
if((a.p2 - a.p1) || (b.p2 - b.p1)){
return PointOnSeg(a.p1, b) || PointOnSeg(a.p2, b) ||
PointOnSeg(b.p1, a) || PointOnSeg(b.p2, a);
}
else return sgn((a.p2 - a.p1) % (b.p1 - a.p1)) * sgn((a.p2 - a.p1) % (b.p2 - a.p1)) <= 0 &&
sgn((b.p2 - b.p1) % (a.p1 - b.p1)) * sgn((b.p2 - b.p1) % (a.p2 - b.p1)) <= 0 ;
}
bool operator / (const Line a, const Seg b){
return sgn(a.v % (b.p1 - a.p)) * sgn(a.v % (b.p2 - a.p)) <= 0;
}
/*--------------------------圆--------------------------*/
struct Circle{
Point p;
double r;
Circle(){};
Circle(Point p1, double r1){p = p1, r = r1;}
Point point(double rad){
return Point(p.x + r * cos(rad), p.y + r * sin(rad));
}
};
bool PointOnCircle(Point p, Circle c){return sgn(Dis(p, c.p) - c.r) == 0;}
bool PointInCircle(Point p, Circle c){return sgn(Dis(p, c.p) - c.r) < 0;}
bool PointOnInCircle(Point p, Circle c){return sgn(Dis(p, c.p) - c.r) <= 0;}
double Area_fan(Vector v1, Vector v2, double r){return 0.5 * angle(v1, v2) * r * r;}
double Area_fan(double rad, double r){return 0.5 * rad * r * r;}
void Poi_LineInterCircle(Line l, Circle c, Point *x, int &nx){
Vector v1 = l.p - c.p;
double A = LenSq(l.v), B = 2 * l.v * v1, C = LenSq(v1) - sq(c.r);
double delta = B*B - 4*A*C;
nx = 0;
if(delta < 0) return;
double t1, t2;
t1 = (-B + (double)sqrt((double)delta)) / (2*A);
t2 = (-B - (double)sqrt((double)delta)) / (2*A);
x[nx++] = l.p + l.v * t1;
if(delta > 0) x[nx++] = l.p + l.v * t2;
}
void Poi_SegInterCircle(Seg s, Circle c, Point *x, int &nx){
Point xt[2];
int nxt;
Poi_LineInterCircle(Line(s.p1, s.p2 - s.p1), c, xt, nxt);
nx = 0;
for(int i = 0; i < nxt; i++){
if(PointOnSeg(xt[i], s)) x[nx++] = xt[i];
}
}
double ComArea_Circle_CenterTri(Circle c, Point p1, Point p2){
//圆和中心三角形的公共面积; c和(c.p, p1, p2)的公共面积
bool oi1 = PointOnInCircle(p1, c), oi2 = PointOnInCircle(p2, c);
if(oi1 && oi2) return Area_Tri(p1, p2, c.p);
else if(oi1 + oi2 == 1){
if(oi1) swap(p1, p2);
Point x[2]; int nx;
Poi_SegInterCircle(Seg(p1, p2), c, x, nx);
return Area_Tri(x[0], p2, c.p) + Area_fan(x[0] - c.p, p1 - c.p, c.r);
}
else{
Point x[2]; int nx;
Poi_SegInterCircle(Seg(p1, p2), c, x, nx);
if(nx == 2){//注意这里的判断,不能判断圆心到线段所在直线的距离,那样是错的
if(Dis(x[1], p1) < Dis(x[0], p1)) swap(x[0], x[1]);
return Area_fan(p1 - c.p, x[0] - c.p, c.r) + Area_Tri(x[0], x[1], c.p) + Area_fan(p2 - c.p, x[1] - c.p, c.r);
}
else return Area_fan(p1 - c.p, p2 - c.p, c.r);
}
}
double ComArea_Circle_Poly(Circle c, Point *p, int np){
//圆和简单多边形的公共面积,前提要保证p逆时针或顺时针排序
if(np <= 2) return 0.0;
double ans = 0.0;
p[np++] = p[0];
for(int i = 0; i < np - 1; i++){
if(p[i] == p[i+1]) continue;
ans += ComArea_Circle_CenterTri(c, p[i], p[i+1]) * sgn((p[i] - c.p) % (p[i+1] - c.p));
}
return fabs(ans);
}
Point readPoi(){
int x = read(), y = read();
return Point(x, y);
}
#define N 10000
int n, P;
Point p[N];
Circle cir;
double erfen(){
double l = 0, r = 10000, mid;
double s = Area_Poly(p, n);
while(r - l > 1e-4){
mid = (l + r) * 0.5;
cir.r = mid;
double coms = ComArea_Circle_Poly(cir, p, n);
if(sgn(coms * 100 - P * s) < 0) l = mid;
else r = mid;
}
return l;
}
int main(){
int T = read();
for(int kase = 1; kase <= T; kase++){
n = read();
for(int i = 0; i < n; i++) p[i] = readPoi();
cir.p = readPoi();
P = read();
double ans = erfen();
printf("Case %d: %.0f\n",kase,ans);
}
return 0;
}