洛谷P1378油滴扩展

题目描述

在一个长方形框子里,最多有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

输出:

50

分析:
这题一看搜索啊,再一看又是圆又是矩形的,还要考虑面积,当时我就想哇这题好难好难啊,然后在dalao的讲解并带嘲讽发现这题真的还不难.就是处理的地方有些麻烦

先讲讲题意吧

1.我们已知一个矩阵.

2.已知在矩阵里我们有n个坐标,这些坐标代表的是这n个油滴的坐标由题目已知这n个油滴可以随意扩展直到碰到矩形边界或碰到另一个油滴

且当一个油滴的坐标被另一个油滴覆盖那么这个油滴是不合法的即这个油滴能扩展的面积为0.

3.我们需要求出在所有的油滴扩展完毕后矩阵剩下的面积最小.

条件及面积的处理

因为题目要求求出最小的剩下面积即我们需要求出这个圆能扩展的最大半径.

圆的半径处理

们可以一个圆在矩阵里能取得最大半径即是这个圆心离这个矩阵四边中最小的距离,这是第一步,接下来因为有其他油滴的存在所以油滴能取得最大半径还要被其他油滴限制

怎么找出它能取得最大半径?简单的画个图就能明白一个圆的在被其他圆限制的条件下它能取得最大半径就是这两个圆之间的欧几里得距离在减去另一个圆的半径

更明确一点.

1.先找到这个圆在矩形中能取的最大半径.

 

int len1=min(abs(xa-x[k]),abs(xb-x[k]));//这里xa,xb,ya,yb为矩阵的对角点坐标
int len2=min(abs(ya-y[k]),abs(yb-y[k]));//因为坐标可能存在负数的情况所以要abs
double r1=min(len1,len2);//取最小

 

2.在其他油滴约束下能取得最大半径

 

for(int i=1;i<=n;i++)
{
    if(vis[i]&&k!=i)//k为当前这个油滴的编号即第几个油滴//这里k!=i当然自己不能和自己比较//vis[i]能比较当然是在我们放有油滴的情况下
    {
        r1=min(r1,dis(x[i],x[k],y[i],y[k])-r[i]);//dis是我声明的求欧几里得距离的函数r[i]半径这个半径是和我们比较的那个圆的半径这里取min值是和上面的r1取最小至于为什么我在上面说的很清楚了
    }
}

 

3.注意

因为题目说了如果当前这个油滴的坐标被其他油滴覆盖的话那这个油滴它不能扩展即我们将它的半径变为0

for(int i=1;i<=n;i++)//所以这里我们需要枚举这n个所有油滴的坐标来判断
{
    if(vis[i]&&k!=i)//这里vis,k和上面的是一样的用处
    {
        if(r[i]>dis(x[i],x[k],y[i],y[k]))//这个地方很容易明白如果这两个点之间的欧几里得距离小于我们要比较的这个圆的半径说明这个圆就被覆盖了
        return 0;我们返回它的半径为0
    }
}

剩下的就没什么可讲的贴代码

代码:

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdlib>
using namespace std;
const int N=1000+100;
const double pi=3.141592;
int n,xa,xb,ya,yb;
double x[N],y[N],keay,r[N];
bool vis[N]; 
double dis(int x,int x1,int y,int y1)//欧几里得
{
    return sqrt((x-x1)*(x-x1)+(y-y1)*(y-y1));
}
double R(int k)//寻找这个圆能取得最大半径
{
    for(int i=1;i<=n;i++)
    {
        if(vis[i]&&k!=i)//不合法将它的半径变为0
        {
            if(r[i]>dis(x[i],x[k],y[i],y[k]))
            return 0;
        }
    }
    int len1=min(abs(xa-x[k]),abs(xb-x[k]));//在矩形里能取得最大半径
    int len2=min(abs(ya-y[k]),abs(yb-y[k]));
    double r1=min(len1,len2);
    for(int i=1;i<=n;i++)
    {
        if(vis[i]&&k!=i)
        {
            r1=min(r1,dis(x[i],x[k],y[i],y[k])-r[i]);//比较在矩形里能取的最大半径和在其他圆约束下能取的最大半径
        }
    }
    return r1;
}
void dfs(int t,double sum)
{
    if(t==n)
    {
        keay=max(keay,sum);
        return;
    }
    for(int i=1;i<=n;i++)
    {
        if(!vis[i])
        {
            r[i]=R(i);//计算每个点能取的最大半径
            vis[i]=true;
            dfs(t+1,sum+pi*r[i]*r[i]);
            vis[i]=false;//回溯
        }
    }
}
int main()
{
    double S;
    cin>>n;
    cin>>xa>>ya>>xb>>yb;
    S=abs(xb-xa)*abs(yb-ya);//S为矩阵面积
    for(int i=1;i<=n;i++)
    cin>>x[i]>>y[i];
    dfs(0,0);
    cout<<(int)(S-keay+0.5);//四舍五入
    return 0;
} 

 

 

 

 

转载于:https://www.cnblogs.com/CCCPKeay/p/9928944.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值