题目描述
在一个长方形框子里,最多有 NN 个相异的点,在其中任何一个点上放一个很小的油滴,那么这个油滴会一直扩展,直到接触到其他油滴或者框子的边界。必须等一个油滴扩展完毕才能放置下一个油滴。那么应该按照怎样的顺序在这 NN 个点上放置油滴,才能使放置完毕后所有油滴占据的总体积最大呢?(不同的油滴不会相互融合)
注:圆的面积公式 V = \pi r^2V=πr2,其中 rr 为圆的半径。
输入格式
第一行,一个整数 NN。
第二行,四个整数 x, y, x', y'x,y,x′,y′,表示长方形边框一个顶点及其对角顶点的坐标。
接下来 NN 行,第 ii 行两个整数 x_i, y_ixi,yi,表示盒子内第 ii 个点的坐标。
输出格式
一行,一个整数,长方形盒子剩余的最小空间(结果四舍五入输出)。
说明/提示
对于 100\%100% 的数据,1 \le N \le 61≤N≤6,坐标范围在 [-1000, 1000][−1000,1000] 内。
AC代码如下:
#include<cstdio>
#include<cmath>
#define PI 3.1415926
using namespace std;
int n, tag[7];//用来标记点
double A[7][2], x, y, x2, y2, R[7], max, dis[7][7];
//R用来标记半径 A用来存储坐标 dis存储点的距离
double abss(double a) //定义一个给浮点数取绝对值的函数
{
return a > 0.0 ? a : -a;
}
void dfs(int step, double s)
{//准备放置第step个油滴,放置前面积为s
int k, i;
double r = 0;//准备放置的油滴的扩散半径
if (step == n + 1)//放完
max = s > max ? s : max;
else
for (k = 1; k <= n; k++)
if (!tag[k])//标记
{
//矩形和已放置的油滴约束了r的大小
r = abss(y2 - A[k][1]);//到水平墙面的距离
if (r > abss(x2 - A[k][0]))
r = abss(x2 - A[k][0]);//到竖直墙面的距离
if (r > abss(y - A[k][1]))
r = abss(y - A[k][1]);//..
if (r > abss(x - A[k][0]))
r = abss(x - A[k][0]);//.
//做法的解释:找出点离哪面墙最近 确定最小的半径
for (i = 1; i <= n; i++)
if (tag[i])//如果这个点有油滴
if (r > dis[k][i] - R[i]) //继续判断 如果r比两个油滴之间的距离减去另一个
r = dis[k][i] - R[i];//的扩散半径还大 那么他最多只能扩散两个油滴之间的
//距离减去另一个油滴的扩散半径
r = r < 0 ? 0 : r;//注意r不能为负
//R为负的情况就是 一个油滴已经覆盖了没有滴的油滴
tag[k] = 1; R[k] = r;
dfs(step + 1, s + PI * r * r);//在下层dfs时 把面积传入下层
tag[k] = 0; R[k] = 0.0;//返回上层 解除标记 并且让半径恢复0
}
}
int main(void)
{
int i, j;
scanf("%d%lf%lf%lf%lf", &n, &x, &y, &x2, &y2);
for (i = 1; i <= n; i++)
scanf("%lf%lf", &A[i][0], &A[i][1]);
//预处理出油滴间距dis
for (i = 1; i <= n; i++)
for (j = 1; j < i; j++)
if (i != j)
dis[i][j] = dis[j][i] = sqrt((A[i][0] - A[j][0]) * (A[i][0] - A[j][0])
+
(A[i][1] - A[j][1]) * (A[i][1] - A[j][1]));
dfs(1, 0.0);
double S = abss(x - x2) * abss(y - y2);//矩形面积
printf("%.0lf", S - max);
return 0;
}