一、算法分析
这道题相当于枚举加模拟,编写代码时最好用自顶向下的方法,先写主函数,把子函数空着,等主函数写完再写子函数。主函数的框架很简单,可以套用stl的next_permutation作为外层循环,然后内层每次计算油滴的半径(算半径可以用子函数实现)即可,然后每次拿局部答案和总答案比较,找出最优解。此外四舍五入的输出方式也要注意。详见代码注释
二、代码及注释
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define x first
#define y second
#define y1 Y1 //y1和头文件冲突
#define left lft
#define right rit
using namespace std;
typedef pair<double,double> PDD;
const int N=10;
const double pi=3.1415926535;
PDD w[10];
int order[10]={0,1,2,3,4,5};
int n;
double r[10]; //油滴的半径
double x1,y1,x2,y2;
double dx,dy;
double up,down,left,right; //只要知道四个边界即可
void calc_mat(){
dx=abs(x1-x2);
dy=abs(y1-y2);
up=max(y1,y2);
down=min(y1,y2);
left=min(x1,x2);
right=max(x1,x2);
}
double calc_dis(int x1,int y1,int x2,int y2){
double dx=x1-x2;
double dy=y1-y2;
return sqrt(dx*dx+dy*dy);
}
void calc_r(int point){
int now=order[point]; //注意不是w里的第point个,而是第order[point]个
double x=w[now].x,y=w[now].y;
r[now]=min(x-left,min(right-x,min(up-y,y-down)));//先和边界比
if(r[now]<0) r[now]=0;
for(int i=0;i<point;i++){ //再和前面的比
int pre=order[i];
double xp=w[pre].x,yp=w[pre].y;
r[now]=min(r[now],max(calc_dis(x,y,xp,yp)-r[pre],0.0));//注意这块不要忘了减r[i],并且注意避免负数出现,调了半个小时发现是这一行忘改了
//这种序号变的一定要谨慎再谨慎
}
}
int main(){
//读入
cin>>n;
cin>>x1>>y1>>x2>>y2;
calc_mat(); //算一些辅助参数,先写主函数,这些可以后面写
for(int i=0;i<n;i++) cin>>w[i].x>>w[i].y;
//枚举排列
double res=0;
do{
double S=0;
for(int i=0;i<n;i++) calc_r(i); //计算第i个油滴的半径
for(int i=0;i<n;i++) S+=pi*r[i]*r[i];
res=max(res,S);
}while(next_permutation(order,order+n));
//输出
cout<<(int)(dx*dy-res+0.5); //注意四舍五入的方式,加0.5取整
return 0;
}