P1378 油滴扩展

暴力出全排列然后求出这种放油的顺序得到的覆盖面积,求所有覆盖面积的最大值,实际做的时候ans保存的是所有半径的平方的和的最大值。

在放一个油滴A的时候,需要和之前放下的油滴B一一比较,如果A和B的距离小于B的半径,那么放不了,否则可能的半径为(r(A)=dist(A, B)-r(B)),和所有点比较后,取最小的r(A),然后还需要用r(A)和A离矩形边框四周的距离取一遍最小,这样就得到了真正的r(A)

另外这题的PI的精确度会影响结果,开始用的3.14, 后来改用系统宏M_PI过了

#include<iostream>
#include<cmath>

using namespace std;

const int N = 10;

#define PII pair<int, int>
#define x first
#define y second

int n;
int down_, up_, left_, right_;
PII p[N];
double r[N]; // 半径
int path[N];
double ans;
int st[N];


double dist(PII a, PII b){
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}

void dfs(int u){
    if(u == n){
        for(int i = 0; i < n; i ++){
            double minv = 1e9;
            for(int j = 0; j < i; j ++){
                double d = dist(p[path[i]], p[path[j]]);
                if(d < r[path[j]]){
                    minv = 0;
                    break;
                }
                minv = min(minv, d - r[path[j]]);
            }
            minv = min(minv, fabs(p[path[i]].x - left_));
            minv = min(minv, fabs(p[path[i]].x - right_));
            minv = min(minv, fabs(p[path[i]].y - up_));
            minv = min(minv, fabs(p[path[i]].y - down_));
            r[path[i]] = minv;
        }
        double maxv = 0;
        for(int i = 0; i < n; i ++) maxv = maxv + r[i] * r[i];
        ans = max(ans, maxv);
        return;
    }
    
    for(int i = 0; i < n; i ++){
        if(st[i] == 0){
            st[i] = 1;
            path[u] = i;
            dfs(u + 1);
            st[i] = 0;
        }
    }
}

int main(){
    cin >> n;
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    
    left_ = min(a, c);
    right_ = max(a, c);
    up_ = max(b, d);
    down_ = min(b, d);
    

    for(int i = 0; i < n; i ++)
        cin >> p[i].x >> p[i].y;
        
    dfs(0);
    
    printf("%.0lf", (up_ - down_) * (right_ - left_) - M_PI * ans);
    
    return 0;
}
原文地址:https://www.cnblogs.com/tomori/p/15342504.html