洛谷 1378 油滴扩展

洛谷 1378 油滴扩展

这道题目的方法并不难想,但能做到一遍AC的也一定是真dalao.

首先,需要注意一下此题的要求,油滴是圆形的,各个油滴只能相离或相切。其次,油滴不能覆盖在已有的油滴上,需要进行特判。

#include<bits/stdc++.h>
using namespace std;
const double pi=3.141592;
int n,x,y,x1,yx;
int a[7][3];
bool v[7];
double res,outt=-1;
double r[7];

double dis(int xx,int yy,int xx1,int yy1)
{
    return sqrt(pow((xx-xx1),2)+pow((yy-yy1),2));
}

dis函数用来计算两点之间的欧几里得距离(勾股定理)。

double minn(int k)
{
    for(int i=1;i<=n;i++)
        if(i!=k&&v[i]==1)
            if(r[i]>dis(a[i][1],a[i][2],a[k][1],a[k][2])) return 0;
    //判断该点坐标是否已被油滴覆盖,是则将该点半径设为零。
    double dist;
    double ans=min(min(abs(a[k][1]-x),abs(a[k][1]-x1)),min(abs(a[k][2]-y),abs(a[k][2]-yx)));
    //先取该点到边界的最小距离。
    for(int i=1;i<=n;i++)
        if(i!=k&&v[i]==1)
        {
            dist=dis(a[i][1],a[i][2],a[k][1],a[k][2])-r[i];
            ans=min(ans,dist);
        }
    //枚举每个已存在的油滴,更新最小值。
    return ans;
}

minn函数用来判断圆的最大半径。

void dfs(int k,double res)
{
    double mm;
    if(k==n)
    {
        outt=max(outt,res);
        return;
    }
    for(int i=1;i<=n;i++)
        if(v[i]==0)
        {
            r[i]=minn(i);
            v[i]=1;
            dfs(k+1,res+pi*r[i]*r[i]);
            v[i]=0;
            r[i]=0;
        }
}

dfs代码,搜索所有可能的顺序。

int main()
{
    scanf("%d",&n);
    scanf("%d%d%d%d",&x,&y,&x1,&yx);
    int s=abs(x-x1)*abs(y-yx);
    //计算总面积
    for(int i=1;i<=n;i++) scanf("%d%d",&a[i][1],&a[i][2]);
    dfs(0,0);
    cout<<int(s-outt+0.5);
    //四舍五入
    return 0;
}

这里需要注意的是输出结果时不能使用如下写法

 cout<<floor(s-outt+0.5);

看似这与 int(s-outt+0.5); 并没有区别,但由于精度的问题,这种写法会WA两个点。
例如:正确答案12345678,而用floor函数会得到1.234567e+006

于是乎,我发现:floor 函数的返回值竟然是是 double 型的!

而double类型的小数点6位之后就无法保证精度了。(我的机子上是6位)。

希望对大家有帮助。

原文地址:https://www.cnblogs.com/yanyiming10243247/p/9238490.html