题目描述

在一个长方形框子里,最多有N(0≤N≤6)个相异的点,在其中任何一个点上放一个很小的油滴,那么这个油滴会一直扩展,直到接触到其他油滴或者框子的边界。必须等一个油滴扩展完毕才能放置下一个油滴。那么应该按照怎样的顺序在这N个点上放置油滴,才能使放置完毕后所有油滴占据的总体积最大呢?(不同的油滴不会相互融合)

注:圆的面积公式V=pirr,其中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
解释:

---------题解(Gelphue),老天爷都找不到更良心的题解了---------

对于这道题(好久没写搜索了呢),对答案起决定性因素的是点拓展的顺序(DFS就是在搜索TA),其次就是对题中各种要求的处理,列表:
  • 1.对于所给长方形,为了统一形式,设点kup为左上角,lap为右下角,且横坐标为Y,纵坐标为X(横坐标为j,纵坐标为i);处理方式为:

        cin >> n;
    cin >> kup.x >> kup.y >> lap.x >> lap.y;
    if (kup.x > lap.x) swap(kup.x, lap.x);//保证左上角的横坐标严格小于右下角的横坐标
    if (kup.y > lap.y) swap(kup.y, lap.y);//保证左上角的纵坐标严格小于右下角的纵坐标
  • 2.对于输入的N个点以及左上,右下坐标,全部自减点kup(坐上坐标),以使长方形的左上角与坐标原点重合,即所有点都在第四象限类,每一的点拓展出去的半径r初始化为0,处理方案为:

       for (int i = 1; i <= n; i++)
        cin >> a[i].x >> a[i].y,
        a[i].x -= kup.x,
        a[i].y -= kup.y,
        a[i].r = 0;
    lap.x -= kup.x, lap.y -= kup.y;
  • 3.预处理每两个点之间的距离,用二维数组贮存,处理方案为:

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j < i; j++)
            dist[i][j] = sqrt(pow(a[i].x - a[j].x, 2) + pow(a[i].y - a[j].y, 2)),
            dist[j][i] = dist[i][j];//a[i]到a[j] 和 a[j]到a[i] 的距离相同
    }
  • 4.用DOUBLE anso表示在不同的拓展顺序中能得到的最大半径和(为 a[1].r^2+a[2].r^2+...+a[N].r^2),输出则用长方形面积(lap.xlap.y)减去总共圆的面积(为 ansoPi),处理方案为(推导过程就不必说了吧):

    dfs(1);
    cout << (int)(lap.x*lap.y - floor(anso*Pi + 1.0 / 2)) << endl;
  • 5.先上一份dfs()的代码:

    void dfs(int d)
    {
    if (d > n)
    {
        double tem_as = 0.0;//统计在这种顺序下的半径平方和
        for (int i = 1; i <= n; i++)
            tem_as += a[i].r_R;//为了优化时间复杂度,把a[i].r*a[i].r单独作为一个成员变量(a[i].r_R)
        anso = max(anso, tem_as);//更性较大值
    }
    for (int i = 1; i <= n; i++)
        if (!use[i])//还没有被搜过
        {
            use[i] = 1;
            {//以下高能,稍后解释*1
                a[i].r = min(min(a[i].x, lap.x - a[i].x), min(a[i].y, lap.y - a[i].y));
                for (int k = 1; k <= n; k++)
                    if (use[k]&& k!=i)
                    {
                        a[i].r = min(a[i].r, dist[i][k] - a[k].r);
                    }
                if (a[i].r < 0) a[i].r = 0;
            }
            a[i].r_R = a[i].r*a[i].r;//更新半径平方
            dfs(d + 1);//进行下一层搜索
            use[i] = 0;
        }
     }
    /*1:解释在这儿:对于正在搜的点,要满足a[i]在长方形以内,则需要满足
    a[i].x-a[i].r>=0,
     a[i].y-a[i].r>=0,
     a[i].x+a[i].r<=lap.x,
     a[i].y+a[i].r<+lap.y.
    所以有了这一句话:
    a[i].r = min(min(a[i].x, lap.x - a[i].x), min(a[i].y, lap.y - a[i].y));
    ;然后就要找所有已经找过的点(a[k])一一和a[i]进行比较,其中a[i].r必须要满足:
       a[i].r+a[k].r<=dist[i][k],
    至于为什么,这里扔一张图
    */

    pic=6381
    https://cdn.luogu.org/upload/pic/6381.png

好了,综上所述,完整的代码在这里

// 动态规划专题(zx).cpp : 定义控制台应用程序的入口点。
//Strengthen self without stopping, and hold world with virtue
//

#include "stdafx.h"
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define Pi (double)3.14159265358
#define redef ios::sync_with_stdio(false),cout.tie(NULL);

int n;
double dist[7][7];
double anso=0;
bool use[7];
struct pl
{
    double x, y, r;
    double r_R;//r_R=:r*r;
    bool operator < (const pl&oth)const
    {
        return (x <= oth.x && y <= oth.y);
    }
}a[7], kup, lap;

void dfs(int d)
{
    if (d > n)
    {
        double tem_as = 0.0;
        for (int i = 1; i <= n; i++)
            tem_as += a[i].r_R;
        anso = max(anso, tem_as);
    }
    for (int i = 1; i <= n; i++)
        if (!use[i])
        {
            use[i] = 1;
            {
                a[i].r = min(min(a[i].x, lap.x - a[i].x), min(a[i].y, lap.y - a[i].y));
                for (int k = 1; k <= n; k++)
                    if (use[k]&& k!=i)
                    {
                        a[i].r = min(a[i].r, dist[i][k] - a[k].r);
                    }
                if (a[i].r < 0) a[i].r = 0;
            }
            a[i].r_R = a[i].r*a[i].r;
            dfs(d + 1);
            use[i] = 0;
        }
}

int main()
{
    redef cin >> n;
    cin >> kup.x >> kup.y >> lap.x >> lap.y;
    {
        if (kup.x > lap.x) swap(kup.x, lap.x);
        if (kup.y > lap.y) swap(kup.y, lap.y);
    }
    for (int i = 1; i <= n; i++)
        cin >> a[i].x >> a[i].y,
        a[i].x -= kup.x,
        a[i].y -= kup.y,
        a[i].r = 0;
    lap.x -= kup.x, lap.y -= kup.y;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j < i; j++)
            dist[i][j] = sqrt(pow(a[i].x - a[j].x, 2) + pow(a[i].y - a[j].y, 2)),
            dist[j][i] = dist[i][j];
    }
    dfs(1);
    cout << (int)(lap.x*lap.y - floor(anso*Pi + 1.0 / 2)) << endl;
    return 0;
}

[动态规划]P1378 油滴扩展的更多相关文章

  1. 洛谷 P1378 油滴扩展 改错

    P1378 油滴扩展 题目描述 在一个长方形框子里,最多有\(N(0≤N≤6)\)个相异的点,在其中任何一个点上放一个很小的油滴,那么这个油滴会一直扩展,直到接触到其他油滴或者框子的边界.必须等一个油 ...

  2. 洛谷P1378 油滴扩展

    P1378 油滴扩展 题目描述 在一个长方形框子里,最多有N(0≤N≤6)个相异的点,在其中任何一个点上放一个很小的油滴,那么这个油滴会一直扩展,直到接触到其他油滴或者框子的边界.必须等一个油滴扩展完 ...

  3. 洛谷 P1378 油滴扩展

    P1378 油滴扩展 题目描述 在一个长方形框子里,最多有N(0≤N≤6)个相异的点,在其中任何一个点上放一个很小的油滴,那么这个油滴会一直扩展,直到接触到其他油滴或者框子的边界.必须等一个油滴扩展完 ...

  4. P1378 油滴扩展——搜索小记

    P1378 油滴扩展 记得这道题好久以前(好像是上个学期?) 就想做了,但是看着里面的半径边界好像很难处理就没做(主要是当时刚学OI(菜还给自己找借口)): 今天上午一直研究SG函数,做的都自闭了,晚 ...

  5. 洛谷P1378 油滴扩展(搜索)

    洛谷P1378 油滴扩展 直接暴力搜索更新答案就可以了. 时间复杂度为 \(O(n!)\) . #include<stdio.h> #include<stdlib.h> #in ...

  6. 洛谷 P1378 油滴扩展 Label:搜索

    题目描述 在一个长方形框子里,最多有N(0≤N≤6)个相异的点,在其中任何一个点上放一个很小的油滴,那么这个油滴会一直扩展,直到接触到其他油滴或者框子的边界.必须等一个油滴扩展完毕才能放置下一个油滴. ...

  7. P1378 油滴扩展

    题目描述 在一个长方形框子里,最多有N(0≤N≤6)个相异的点,在其中任何一个点上放一个很小的油滴,那么这个油滴会一直扩展,直到接触到其他油滴或者框子的边界.必须等一个油滴扩展完毕才能放置下一个油滴. ...

  8. P1378 油滴扩展 dfs回溯法

    题目描述 在一个长方形框子里,最多有N(0≤N≤6)个相异的点,在其中任何一个点上放一个很小的油滴,那么这个油滴会一直扩展,直到接触到其他油滴或者框子的边界.必须等一个油滴扩展完毕才能放置下一个油滴. ...

  9. luogu P1378 油滴扩展

    题目描述 在一个长方形框子里,最多有N(0≤N≤6)个相异的点,在其中任何一个点上放一个很小的油滴,那么这个油滴会一直扩展,直到接触到其他油滴或者框子的边界.必须等一个油滴扩展完毕才能放置下一个油滴. ...

随机推荐

  1. 谦先生的程序员日志之我的hadoop大数据生涯一

    从一个初级程序员到高级程序员的经历 你好!我是谦先生,我是茫茫程序猿中的一猿,平凡又执着. 刚入行的时候说实话,啥都不懂,就懂点皮毛的java,各种被虐狗的感觉.又写js又写css又写后台...慢慢被 ...

  2. 基于Eclipse IDE的Ardupilot飞控源码阅读环境搭建

    基于Eclipse IDE的Ardupilot飞控源码阅读环境搭建 作者:Awesome 日期:2017-10-21 需准备的软件工具 Ardupilot飞控源码 PX4 toolchain JAVA ...

  3. 开始Java8之旅(四) --四大函数接口

    前言   Java8中函数接口有很多,大概有几十个吧,具体究竟是多少我也数不清,所以一开始看的时候感觉一脸懵逼,不过其实根本没那么复杂,毕竟不应该也没必要把一个东西设计的很复杂. 几个单词   在学习 ...

  4. Fiddler使用总结(一)

    与后端数据通信是前端日常开发的重要一环,在与后端接口联调的时候往往需要通过查看后端返回的数据进行调试.如果在PC端,Chrome自带的DevTools就已经足够用了,Network面板可以记录所有网络 ...

  5. (转)关于Tomcat的点点滴滴(体系架构、处理http请求的过程、安装和配置、目录结构、设置压缩和对中文文件名的支持、以及Catalina这个名字的由来……等)

    转自:http://itfish.net/article/41668.html   总结Tomcat的体系架构.处理http请求的过程.安装和配置.目录结构.设置压缩和对中文文件名的支持.以及Cata ...

  6. Memcached查找命令

    Memcached各个查找命令的语法格式都类似,且有相同的参数和参数含义,先将可能出现的各个参数的意义说明如下 key:键值 key-value 结构中的 key,用于查找缓存值. noreply(可 ...

  7. Call From master/192.168.128.135 to master:8485 failed on connection exception: java.net.ConnectException: Connection refused

    hadoop集群搭建了ha,初次启动正常,最近几天启动时偶尔发现,namenode1节点启动后一段时间(大约10几秒-半分钟左右),namenode1上namenode进程停掉,查看日志: -- :: ...

  8. JAVA 的 Date、Calendar的常用用法

    一.Date与String的互转用法,这里需要用到SimpleDateFormat Date date = new Date();        //设置格式        SimpleDateFor ...

  9. c++连接数据库 在vc6.0

    配置相关环境 我的mysql安装路径为E:\mysql-5.5.28-win32所以要在VC中设置include路径和lib的路径. 添加MySql的include目录到VC工作台中Project-& ...

  10. Bluetooth Obex

    OPP 1.2 which uses OBEX over L2CAP. OPP 1.1 connection and transfer happens over RFCOMM->L2CAP.