• bzoj1185 [HNOI2007]最小矩形覆盖


    1185: [HNOI2007]最小矩形覆盖

    Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special Judge
    Submit: 1945  Solved: 853
    [Submit][Status][Discuss]

    Description

     

    分析:有一个比较显然的结论:最小的矩形一定有一条边在凸包上.利用旋转卡壳求出对应边的最远点.这两个是比较容易做到的,有点难的是如何求另外两边的最远点.

              另外两个点的位置显然是单峰函数,可以利用旋转卡壳的思想.关键就是如何以当前凸包的边为x轴来找最远的点,这里不能单单只找横坐标最大/小的点.利用点积,就能将边投影到凸包的边上去,也就是比较点积的大小.那么思路基本上就出来了:底边固定了,最高点利用叉积(旋转卡壳)来确定,左右两个点用点积来确定.最后求矩形的长和高,利用叉积求高,点积求长.求四个顶点的位置则利用向量的伸缩(比例).

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const double eps = 1e-10;
    
    int n,tot;
    double maxx = 1e12;
    struct node
    {
        double x,y;
        node() {}
        node(double _x,double _y) :x(_x),y(_y) {}
    } e[50010],ans[10],p[50010];
    
    double dist(node a,node b)
    {
        return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }
    
    double det(node a,node b)  //叉积
    {
        return a.x * b.y - a.y * b.x;
    }
    
    double dot(node a,node b)  //点积
    {
        return a.x * b.x + a.y * b.y;
    }
    
    node operator + (node a,node b)
    {
        return node(a.x + b.x,a.y + b.y);
    }
    
    node operator - (node a,node b)
    {
        return node(a.x - b.x,a.y - b.y);
    }
    
    node operator * (node a,double x)
    {
        return node(a.x * x,a.y * x);
    }
    
    int three(double x)  //三态函数
    {
        if (fabs(x) < eps)
            return 0;
        if (x > eps)
            return 1;
        return -1;
    }
    
    bool operator < (node a,node b)  //输出比较
    {
        if (three(a.y - b.y) == 0)
        {
            if (three(a.x - b.x) == -1)
                return true;
            return false;
        }
        if (three(a.y - b.y) == -1)
            return true;
        return false;
    }
    
    bool cmp(node a,node b)
    {
        double temp = det(a - e[1],b - e[1]);
        if (temp != 0)
            return temp > 0;
        return dist(a,e[1]) < dist(b,e[1]);
    }
    
    void solve()  //求凸包
    {
        int id = 1;
        for (int i = 1; i <= n; i++)
            if (three(e[i].x - e[id].x) == -1 || (three(e[i].x - e[id].x) == 0 && three(e[i].y - e[id].y) == -1))
                id = i;
        if (id != 1)
            swap(e[1],e[id]);
        sort(e + 2,e + 1 + n,cmp);
        p[++tot] = e[1];
        for (int i = 2; i <= n; i++)
        {
            while (tot >= 2 && det(e[i] - p[tot - 1],p[tot] - p[tot - 1]) >= 0)
                tot--;
            p[++tot] = e[i];
        }
    }
    
    void solve2()
    {
        p[tot + 1] = p[1];
        int left = 1,right = 1,up = 1;
        for (int i = 1; i <= tot; i++)
        {
            while (three(fabs(det(p[up + 1] - p[i + 1],p[i] - p[i + 1])) - fabs(det(p[up] - p[i + 1],p[i] - p[i + 1]))) >= 0)
                up = up % tot + 1;  //最高点
            while (three(dot(p[i + 1] - p[right + 1],p[i] - p[i + 1]) - dot(p[i + 1] - p[right],p[i] - p[i + 1])) >= 0)
                right = right % tot + 1;   //最右边的点
            if (i == 1)
                left = right;
            while (three(dot(p[i] - p[left + 1],p[i + 1] - p[i]) - dot(p[i] - p[left],p[i + 1] - p[i])) >= 0)
                left = left % tot + 1;
            double D = dist(p[i],p[i + 1]);
            double H = det(p[up] - p[i + 1],p[i] - p[i + 1]) / D;
            double L = fabs(dot(p[i + 1] - p[i],p[left] - p[i + 1])) / D + fabs(dot(p[i + 1] - p[i],p[right] - p[i + 1])) / D; //底边
            if (three(L * H - maxx) == -1)
            {
                maxx = L * H;
                ans[0] = p[i] + (p[i + 1] - p[i]) * ((fabs(dot(p[i + 1] - p[i],p[right] - p[i + 1])) / D + D) / D);
                ans[1] = ans[0] + (p[right] - ans[0]) * (H / dist(p[right],ans[0]));
                ans[2] = ans[1] + (p[up] - ans[1]) * (L / dist(p[up],ans[1]));
                ans[3] = ans[2] + (p[left] - ans[2]) * (H / dist(p[left],ans[2]));
            }
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        for (int i = 1; i <= n; i++)
            scanf("%lf%lf",&e[i].x,&e[i].y);
        solve();
        solve2();
        int id = 0;
        for (int i = 1; i < 4; i++)
            if (ans[i] < ans[id])
                id = i;
        printf("%.5lf
    ",maxx);
        for (int i = 0; i < 4; i++)
            printf("%.5lf %.5lf
    ",ans[(i + id) % 4].x,ans[(i + id) % 4].y);
    
        return 0;
    }
  • 相关阅读:
    pip命令提示unknow or unsupported command install解决方法
    SSH登录慢解方案
    python/shell脚本报异常^M: bad interpreter: No such file or directory
    MySQL中自增ID起始值修改方法
    Centos给文件设置了777权限仍不能访问解决方案
    CentOS7下安装mysql5.7
    CentOS7下使用yum安装MariaDB
    sublime text 3启动报错"swallow_startup_errors"解决方法
    一个清除数组的方法在 Kotlin、Java、C#和Nim上的性能测试
    国外立交桥设计参考资料
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8125752.html
Copyright © 2020-2023  润新知