原题:P1378 油滴扩展
题面:
P1378 油滴扩展
题目描述
在一个长方形框子里,最多有 个相异的点,在其中任何一个点上放一个很小的油滴,那么这个油滴会一直扩展,直到接触到其他油滴或者框子的边界。必须等一个油滴扩展完毕才能放置下一个油滴。那么应该按照怎样的顺序在这 个点上放置油滴,才能使放置完毕后所有油滴占据的总面积最大呢?(不同的油滴不会相互融合)
注:圆的面积公式 ,其中 为圆的半径。
输入格式
第一行,一个整数 。
第二行,四个整数 ,表示长方形边框一个顶点及其对角顶点的坐标。
接下来 行,第 行两个整数 ,表示盒子内第 个点的坐标。
输出格式
一行,一个整数,长方形盒子剩余的最小空间(结果四舍五入输出)。
输入输出样例 #1
输入 #1
2
20 0 10 10
13 3
17 7
输出 #1
50
说明/提示
对于 的数据,,坐标范围在 内。
很久没有做搜索题了,所以最近准备练一下搜索。
看一眼题目,感觉比较毒瘤,是带浮点数计算的,但思路并不难,由于 ,所以我们根本不需要任何剪枝,直接暴力搜索方案然后求得剩余面积最小值即可。
这道题主要的是如何计算每个油滴最多能扩展的大小。题目说:当油滴碰到其他油滴或者矩形的边界的时候,就停止扩展。所以对于每个油滴,我们需要计算从它到周围最近的油滴或者矩形边界的距离,而这个距离就是它能扩展的半径。
具体地,在搜索的时候,我们用一个 数组来记录前面已经用过的油滴的半径,然后枚举计算当前油滴和前面油滴间的距离,取距离的最小值。同时需要注意,设两个油滴间的距离为 ,然后前面的油滴的扩展半径为 ,若 ,则说明当前这个油滴已经被前面这个油滴覆盖,不能再计入扩展面积,直接跳过。
然后如果一个油滴没有被任何油滴覆盖,则取得它与其他油滴的最小距离后,再计算它到矩形四条边边界的最小距离,最终取最小值,即为当前油滴的扩展半径,计入总面积后,进行下一步搜索即可。
#include <iostream>
#include <cstring>
#include <iomanip>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(x) cout << #x << "=" << x << "\n";
int n;
const int maxn = 10;
const double pi = 3.1415926535;
double x[maxn], y[maxn];
double r[maxn];
bool used[maxn];
double xa, ya, xb, yb;
double ans, area;
double calc_dis(double x1, double y1, double x2, double y2)
{
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
double calc_area(double r)
{
return pi * r * r;
}
void dfs(double cur)
{
ans = min(ans, area - cur);
for (int i = 1; i <= n; i++)
{
bool is_lap = false;
double cur_r = 1e9;
if (used[i])
continue;
for (int j = 1; j <= n; j++)
{
if (i == j)
continue;
if (used[j])
{
double dis = calc_dis(x[i], y[i], x[j], y[j]);
if (dis <= r[j])
{
is_lap = true;
break;
}
cur_r = min(cur_r, dis - r[j]);
}
}
if (is_lap)
continue;
cur_r = min(cur_r, min(min(xb - x[i], x[i] - xa), min(yb - y[i], y[i] - ya)));
r[i] = cur_r;
used[i] = true;
dfs(cur + calc_area(cur_r));
r[i] = 0;
used[i] = false;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
cin >> xa >> ya >> xb >> yb;
double temp;
temp = xa, xa = min(xa, xb), xb = max(temp, xb);
temp = ya, ya = min(ya, yb), yb = max(temp, yb);
for (int i = 1; i <= n; i++)
cin >> x[i] >> y[i];
ans = area = (xb - xa) * (yb - ya);
dfs(0);
cout << int(round(ans));
return 0;
}
值得注意的是, 函数的返回值为 类型,所以最后我们还需要进行 的强制转换,不然的话有时会输出小数点,然后你会获得 的好成绩。