2020hdu多校第一场 待补题

比赛链接

 

1002

一、题意

n个点的凸多边形草地,想要把草地全部除干净。有一个半径为r的圆形除草机,单位面积的草花费是B,人工除草单位面积花费是A。使用除草器时不能越过多边形的边界,即除草器的一部分在多边形外部是不合法的。问除草结束的最小花费

多个测例。1 \leqslant T \leqslant 100

数据范围:n \leqslant 200 , 0 \leqslant r \leqslant 10000 , 0 \leqslant A , B \leqslant 1000 , \left | x_i \right | , \left | y_i \right | \leqslant 1000

二、题解

凸多边形的每条边向多边形内部移动r距离,通过半平面交形成一个新的凸多边形,假设面积是a,周长是b,那么可以知道圆可以覆盖的面积是 a+b*r+\pi * r ^ 2。然后判断大小,选择最小值即可。

三、代码

#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 ;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值