• 矩形覆盖


    题目描述

    在平面上有 n 个点(n <= 50),每个点用一对整数坐标表示。
    这些点可以用 k 个矩形(1<=k<=4)全部覆盖,矩形的边平行于坐标轴。问题是当 n 个点坐标和 k 给出后,怎样才能使得覆盖所有点的 k 个矩形的面积之和为最小呢。约定:覆盖一个点的矩形面积为 0;覆盖平行于坐标轴直线上点的矩形面积也为0。各个矩形必须完全分开(边线与顶点也都不能重合)。

    输入输出格式

    输入格式:
    n k xl y1 x2 y2 … …

    xn yn (0<=xi,yi<=500)

    输出格式:
    输出至屏幕。格式为:

    一个整数,即满足条件的最小的矩形面积之和。

    输入输出样例

    输入样例#1:
    4 2
    1 1
    2 2
    3 6
    0 7
    输出样例#1:
    4

    分析:这是一道典型的搜索题(毕竟在luogu的分类也是搜索),k的范围不大,所以我们可以以k为基准,讨论每一个点属于那个矩形,在搜索的同时判断这种方法是否合法,不合法就直接进行剪枝。我在一开始码这道题目的时候,思路是把n个点随机分成k份,再判断这种方式合不合法,这样会导致时间效率过低。在参考了某位大神的代码之后,对自己的代码进行了改进,认为还是本题很好的解决方法的,参考如下(有详细的注释O(∩_∩)O~):

    这里写代码片
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    int n,m,ans=10000000;
    struct node{
        int x,y;
    };
    node a[510];
    struct node2{
        int l,r,u,d;
        bool f;
    };
    node2 p[5];
    
    bool zai(node2 a,int x,int y)
    {
        if (x<=a.r&&x>=a.l&&y<=a.u&&y>=a.d)
          return 1;
        return 0;
    }
    
    bool pd(node2 a,node2 b)  //判断是否包含 
    {
        if (zai(a,b.l,b.u)) return 1;  //左上角   任何一个顶点在已知矩阵内就不合法 
        if (zai(a,b.l,b.d)) return 1;  //左下角 
        if (zai(a,b.r,b.u)) return 1;  //右上角 
        if (zai(a,b.r,b.d)) return 1;  //右下角 
        return 0;
    }
    
    int ss(int t)
    {
        int i,j,v=0;
        for (i=1;i<=m;i++)  //在进行选点之前,先把当前状态判断一下 
        {
            if (p[i].f)  //征用了这块地 
            {
                for (j=1;j<=m;j++)  
                {
                    if (i!=j&&p[j].f&&pd(p[i],p[j]))  //j也被征用,同时j在i内 
                       return 0;  //这种方案不合法,直接回溯 
                }
            }
            v+=(p[i].r-p[i].l)*(p[i].u-p[i].d);  //合法时加入面积 
        }
        if (v>=ans)  //当前的面积已经比ans大了,不合法,回溯 
           return 0;
        if (t>n)  //所有点都加入了,而且通过了上面的考验 
        {
            ans=v;
            return 0;
        }
        for (i=1;i<=m;i++)  //真正的搜索开始啦,循环我们要把这个点加入哪块矩阵 
        {
            node2 tmp=p[i];
            if (p[i].f==0)  //崭新的矩阵 
            {
                p[i].f=1;
                p[i].l=p[i].r=a[t].x;
                p[i].u=p[i].d=a[t].y;
                ss(t+1);
                p[i]=tmp;  //回溯要彻底 
            } 
            else
            {
                p[i].l=min(p[i].l,a[t].x);  //维护边界值 
                p[i].r=max(p[i].r,a[t].x);
                p[i].u=max(p[i].u,a[t].y);
                p[i].d=min(p[i].d,a[t].y);
                ss(t+1);
                p[i]=tmp;
            }
        }
    }
    
    int main()
    {
        int i=1;
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++)
          scanf("%d%d",&a[i].x,&a[i].y);
        ss(1);
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    检查你的iOS程序是否正在被调试
    破解从 AppStore 下载的 IPA
    在 iOS 中如何发短信
    关于移动应用UI部分管理的一些思考
    在 iOS 应用中实现飞行模式提醒
    如何在iOS应用中拨打电话,并让用户确认
    [转]How to hide inputAccessoryView without dismissing keyboard
    php 读取文件并以文件方式下载
    一个session,判断用户唯一的技巧
    一个简单文件上传代码
  • 原文地址:https://www.cnblogs.com/wutongtong3117/p/7673660.html
Copyright © 2020-2023  润新知