题目描述
在一个长方形框子里,最多有N(0≤N≤6)个相异的点,在其中任何一个点上放一个很小的油滴,那么这个油滴会一直扩展,直到接触到其他油滴或者框子的边界。必须等一个油滴扩展完毕才能放置下一个油滴。那么应该按照怎样的顺序在这N个点上放置油滴,才能使放置完毕后所有油滴占据的总体积最大呢?(不同的油滴不会相互融合)
注:圆的面积公式V=pi*r*r,其中r为圆的半径。
输入输出格式
输入格式:
第1行一个整数N。
第2行为长方形边框一个顶点及其对角顶点的坐标,x,y,x’,y’。
接下去N行,每行两个整数xi,yi,表示盒子的N个点的坐标。
以上所有的数据都在[-1000,1000]内。
输出格式:
一行,一个整数,长方形盒子剩余的最小空间(结果四舍五入输出)
输入输出样例
输入样例#1:
2 20 0 10 10 13 3 17 7
输出样例#1:
50
【题解】
思路是枚举全排列,对于每个圆计算其面积。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
const int maxn=10;
#define pi 3.141592653
using namespace std;
int n,x[maxn],y[maxn],xa,xb,ya,yb;
double ans=0.0,t,R[maxn];
bool done[maxn];
double dst(int x1,int y1,int x2,int y2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
void cal(int id){
R[id]=100000000.0;
R[id]=min(x[id]-xa,xb-x[id]);
R[id]=min(min(y[id]-ya,yb-y[id]),(int)R[id]);
for(int i=0;i<n;i++)
if(done[i]&&i!=id){
double d=dst(x[id],y[id],x[i],y[i])-R[i];//圆心距-目标圆的半径
if(d<0){
R[id]=0.0;
break;
}
if(d<R[id])R[id]=d;
}
t+=R[id]*R[id]*pi;
}
int main()
{
int a[maxn];
scanf("%d%d%d%d%d",&n,&xa,&ya,&xb,&yb);
if(xa>xb)swap(xa,xb);if(ya>yb)swap(ya,yb);//矩形的输入检测
for(int i=0;i<n;i++){
scanf("%d%d",&x[i],&y[i]);
a[i]=i;
}
do{
t=0.0;
memset(done,0,sizeof(done));
memset(R,0,sizeof(R));
for(int i=0;i<n;i++){
cal(a[i]);//计算每个圆的面积,手贱在刚开始下意识调用cal(i)
done[a[i]]=true;//标记
}
if(t>ans)ans=t;
}while(next_permutation(a,a+n));//枚举全排列
printf("%.lf\n",(double)(xb-xa)*(yb-ya)-ans);//注意!是剩余面积,样例的圆面积与剩余面积相等--
return 0;
}