洛谷 P1378 油滴扩展
题目链接:油滴扩展
思路
枚举油滴滴下的顺序,然后依次判断每个油滴扩展的半径。然后每次计算出当前油滴能扩散的最大半径,通过使用当前油滴与边长的距离。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 10;
const double PI = 3.1415926535;
bool s[maxn];
double x[maxn], y[maxn], r[maxn], xa, ya, xb, yb, ansmax;
int n;
// 计算当前油滴的扩散半径
double cal(int i) {
// 计算当前油滴与长方形边框边界的最小距离
double s1 = min(abs(x[i] - xa), abs(x[i] - xb));
double s2 = min(abs(y[i] - ya), abs(y[i] - yb));
double ans = min(s1, s2);
// 计算当前油滴与其他油滴扩散的圈的半径最小值
for (int j = 1; j <= n; j++)
if (i != j && s[j]) {
double d =
sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
ans = min(ans, max(d - r[j], 0.0)); // 如果距离都小于0了,那我还要你有何用
}
return ans;
}
// 深搜枚举每个节点的滴落顺序
void dfs(int k, double sum) {
// 当滴落的油滴数大于n时,取油滴覆盖位置的最大值
if (k > n) {
ansmax = max(ansmax, sum);
return;
}
for (int i = 1; i <= n; i++) {
// 当前油滴是否被枚举,没有则枚举并计算当前油滴扩散的半径
if (!s[i]) {
r[i] = cal(i);
s[i] = 1;
dfs(k + 1, sum + r[i] * r[i] * PI);
s[i] = 0;
}
}
}
int main() {
double ss;
scanf("%d", &n);
scanf("%lf%lf%lf%lf", &xa, &ya, &xb, &yb);
ss = abs(xa - xb) * abs(ya - yb);
for (int i = 1; i <= n; i++)
scanf("%lf%lf", &x[i], &y[i]);
dfs(1, 0);
printf("%d", int(ss - ansmax + 0.5)); // 四舍五入
return 0;
}