题目描述
在一个长方形框子里,最多有 N 个相异的点,在其中任何一个点上放一个很小的油滴,那么这个油滴会一直扩展,直到接触到其他油滴或者框子的边界。必须等一个油滴扩展完毕才能放置下一个油滴。那么应该按照怎样的顺序在这 N 个点上放置油滴,才能使放置完毕后所有油滴占据的总体积最大呢?(不同的油滴不会相互融合)
注:圆的面积公式 V=πr2,其中 r 为圆的半径。
输入格式
第一行,一个整数 N。
第二行,四个整数 x,y,x′,y′,表示长方形边框一个顶点及其对角顶点的坐标。
接下来 N 行,第 i 行两个整数 ixi,yi,表示盒子内第 i 个点的坐标。
输出格式
一行,一个整数,长方形盒子剩余的最小空间(结果四舍五入输出)。
此题目的思路比较简单,但是细节比较多。首先是计算油滴所占面积的问题,我们计算每滴油的半径要取圆心于长方形框的四条边的距离以及与其他圆距离的最小值(与其他油滴的距离的计算方式是两个圆心的距离减去另一个圆的半径,需要注意的是一旦两个圆的距离小于零就说明此油滴被另一个油滴包含了)。其次是题目所有数据用double存储,为了保证结果的准确性,尽量把Π往后多写几位,结果的四舍五入用round函数即可。
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
bool vis[30];
double n,x,y,dx,dy,ans=0,s,r[30];
double pai=3.1415926535;
struct node{
double x,y;
}q[30];//存储每个点的坐标
double findr(int i)计算此点油滴 的半径
{
double minr;
double r1=min(abs(q[i].x-x),abs(q[i].x-dx));
double r2=min(abs(q[i].y-y),abs(q[i].y-dy));
minr=min(r1,r2);//取离边界最近的距离
for(int j=0;j<n;j++)
{
if(i!=j&&vis[j])
{
double rr;
rr=sqrt((q[i].x-q[j].x)*(q[i].x-q[j].x)+(q[i].y-q[j].y)*(q[i].y-q[j].y))-r[j];//与另一个圆的距离
if(rr>=0)
minr=min(rr,minr);
else
minr=0;
}
}
return minr;
}
void dfs(int m,double sum)
{
if(m==n)
{
ans=max(ans,sum);
return ;
}
for(int i=0;i<n;i++)
{
if(!vis[i])
{
vis[i]=true;
r[i]=findr(i);
dfs(m+1,sum+r[i]*r[i]*pai);
vis[i]=false;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>x>>y>>dx>>dy;
for(int i=0;i<n;i++)
cin>>q[i].x>>q[i].y;
s=abs((x-dx)*(y-dy));
dfs(0,0);
double v=s-ans;//剩余面积的最小值就是边框面积减去油滴面积的最大值
cout<<(int)round(v)<<endl;
return 0;
}