(细节处理)洛谷P1378油滴扩展

一、算法分析

这道题相当于枚举加模拟,编写代码时最好用自顶向下的方法,先写主函数,把子函数空着,等主函数写完再写子函数。主函数的框架很简单,可以套用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;
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值