比赛链接
1002
一、题意
个点的凸多边形草地,想要把草地全部除干净。有一个半径为
的圆形除草机,单位面积的草花费是
,人工除草单位面积花费是
。使用除草器时不能越过多边形的边界,即除草器的一部分在多边形外部是不合法的。问除草结束的最小花费
多个测例。
数据范围:
二、题解
凸多边形的每条边向多边形内部移动距离,通过半平面交形成一个新的凸多边形,假设面积是
,周长是
,那么可以知道圆可以覆盖的面积是
。然后判断大小,选择最小值即可。
三、代码
#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x) (int)x.size()
#define cl(x) x.clear()
#define all(x) x.begin() , x.end()
#define rep(i , x , n) for(int i = x ; i <= n ; i ++)
#define per(i , n , x) for(int i = n ; i >= x ; i --)
#define mem0(x) memset(x , 0 , sizeof(x))
#define mem_1(x) memset(x , -1 , sizeof(x))
#define mem_inf(x) memset(x , 0x3f , sizeof(x))
#define debug(x) cerr << #x << " = " << x << '\n'
#define ddebug(x , y) cerr << #x << " = " << x << " " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef long double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const db eps = 1e-12 ;
const db pi = acosl(-1.0) ;
db r ;
int sgn(db x)
{
if(x < -eps) return -1 ; else if (x > eps) return 1 ; else return 0 ;
}
void print(int num , db x)
{
cout << fixed << setprecision(num) << x << '\n' ;
}
struct point
{
db x , y ;
point operator + (const point& s)const{return (point){x + s.x , y + s.y} ;}
point operator - (const point& s)const{return (point){x - s.x , y - s.y} ;}
point operator * (const db& k)const{return (point){x * k , y * k} ;}
point operator / (const db& k)const{return (point){x / k , y / k} ;}
db get_angle(){return atan2(y , x) ;} //极角
} p[maxn] ;
db cross(point s , point t){return s.x * t.y - s.y * t.x ;} // 叉积
db dot(point s , point t){return s.x * t.x + s.y * t.y ;} // 点积
db sq(db x)
{
return x * x ;
}
db dis(point s , point t)
{
return sqrtl(sq(s.x - t.x) + sq(s.y - t.y)) ;
}
struct cmp
{
point p ;
cmp(const point &p0) {p = p0;}
bool operator()(const point &aa, const point &bb)
{
point a = aa, b = bb;
int d = sgn(cross(a - p , b - p)) ;
if(d == 0) return sgn(dis(a , p) - dis(b , p)) < 0 ;
return d > 0 ;
}
} ;
struct line
{
point s , t ;
db ang ;
line(){}
line(point s1 , point t1)
{
s = s1 , t = t1 ;
ang = t1.get_angle() ;
}
bool operator < (const line& l1)const{return ang < l1.ang ;}
} q[maxn] ;
line move_left(point s , point t) //从s->t的有向线段向左边平移r距离
{
db len = dis(s , t) ;
db vx = -(t.y - s.y) ;
db vy = t.x - s.x ;
db nxt_sx = s.x + r * vx / len ;
db nxt_sy = s.y + r * vy / len ;
db nxt_tx = t.x + r * vx / len ;
db nxt_ty = t.y + r * vy / len ;
return (line){(point){nxt_sx , nxt_sy} , (point){nxt_tx - nxt_sx , nxt_ty - nxt_sy}} ;
}
struct Polygon
{
int n ;
point intersect(point s1 , point t1 , point s2 , point t2) // 线段交点(点+向量表示直线)
{
db x = cross(t2 , s1 - s2) / cross(t1 , t2) ;
return s1 + t1 * x ;
}
point intersect(line l1 , line l2){ return intersect(l1.s , l1.t , l2.s , l2.t) ;}
bool onRight(point l1 , line l2){return sgn(cross(l2.t , l1 - l2.s)) < 0 ;}
bool getHalfplaneIntersection(vector<line>L , vector<point> &sol) // 半平面交
{
int n = sz(L) , l , r ;
sort(all(L)) ;
l = 0 , r = 0 ;
q[0] = L[0] ;
rep(i , 1 , n - 1)
{
while(l < r && onRight(p[r - 1] , L[i])) r -- ;
while(l < r && onRight(p[l] , L[i])) l ++ ;
q[++ r] = L[i] ;
if (sgn(cross(q[r].t , q[r - 1].t)) == 0)
{
r -- ;
if(!onRight(L[i].s , q[r])) q[r] = L[i] ;
}
if(l < r) p[r - 1] = intersect(q[r - 1] , q[r]) ;
}
while(l < r && onRight(p[r - 1] , q[l])) r -- ;
if (r - l <= 1) return 0 ; // 交不存在
cl(sol) ;
p[r] = intersect(q[l] , q[r]) ;
rep(i , l , r) sol.pb(p[i]) ;
return 1 ;
}
db area(vector<point> P) // 多边形面积
{
int n = sz(P) ;
db area = 0.0 ;
rep(i , 0 , n - 1) area += cross(P[i] - P[0] , P[(i + 1) % n] - P[0]) ;
return fabs(area / 2.0) ;
}
db circumference(vector<point>P)
{
int n = sz(P) ;
db res = 0 ;
rep(i , 0 , n - 1) res += dis(P[i] , P[(i + 1) % n]) ;
return res ;
}
} polygon ;
vector<point> P , hpi ; // 多边形和半平面交
vector<line> L ; // 所有半平面
int main()
{
ios ;
int T ;
cin >> T ;
while(T --)
{
int n ;
db A , B ;
cin >> n >> r >> A >> B ;
P = vector<point>(n) ;
rep(i , 0 , n - 1) cin >> P[i].x >> P[i].y ;
point ttt = P[0] ;
rep(i , 1 , n - 1) if(sgn(P[i].x - ttt.x) < 0 || sgn(P[i].x - ttt.x) == 0 && sgn(P[i].y - ttt.y) < 0) ttt = P[i] ;
sort(all(P) , cmp(ttt)) ;
db sum = polygon.area(P) ;
db ans = sum * A ;
cl(L) ;
rep(i , 0 , n - 1) L.pb(move_left(P[i] , P[(i + 1) % n])) ;
if(polygon.getHalfplaneIntersection(L , hpi))
{
db area = polygon.area(hpi) ;
db length = polygon.circumference(hpi) ;
area = area + length * r + pi * r * r ;
ans = min(ans, area * B + (sum - area) * A) ;
}
print(12 , ans) ;
}
return 0 ;
}