zoukankan      html  css  js  c++  java
  • noip2002 矩形覆盖

    题目描述

    在平面上有 n 个点(n <= 50),每个点用一对整数坐标表示。例如:当 n=4 时,4个点的坐标分另为:p1(1,1),p2(2,2),p3(3,6),P4(0,7),见图一。

    这里写图片描述

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

    题解:

    发现,一个最优解一定是在原来的矩形基础上,横切一刀,或者纵切一刀得到。

    所以,就直接搜索dfs

    开一个支持垃圾回收的数组记录当前块所有点。

    int dfs(id,re)

    表示把id所代表的块分成re块,最小的面积总和。

    然后直接暴搜即可。

    dfs的时候,注意三点:

    1.数组本身记录的是点的编号,而循环的i是编号的重编号。访问采用p[mem[id][i]] 而不是 p[i]

    2.每次在搜索树子树里面,需要重新按照x,y排序两次,不能直接用id排序,因为id返回之后,作为le或者ri还要按照顺序用,排序了就直接打乱了。

    3.回溯之前,把用到的数组都删掉。dele(tmp),dele(le),dele(ri)注意,自己id不能删,因为回溯之后还可能要用。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=52;
    const int inf=0x3f3f3f3f;
    int n,k;
    int ans=inf;
    struct node{
        int x,y;
    }p[N];
    int mem[200][54];
    int tmp[54];
    int dp[200],dc,cnt;
    bool cmp1(int a,int b){//heng zuobiao paixu
        return p[a].x<p[b].x;
    }
    bool cmp2(int a,int b){//zong zuobiao paixu
        return p[a].y<p[b].y;
    }
    int nc(){
        int r=dc?dp[dc--]:++cnt;
        return r;
    }
    void dele(int o){
        dp[++dc]=o;
    }
    int dfs(int id,int sz,int re){
        if(sz<=re) return 0;
        if(re==1){
            int u,d,l,r;
            u=-1,d=inf,l=inf,r=-1;
            for(int i=1;i<=sz;i++){
                u=max(u,p[mem[id][i]].y);
                d=min(d,p[mem[id][i]].y);
                l=min(l,p[mem[id][i]].x);
                r=max(r,p[mem[id][i]].x);
            }
            int sum=(u-d)*(r-l);
            
            return sum;
        }
        
        int ret=inf;
        int tmp=nc();
        memcpy(mem[tmp],mem[id],sizeof mem[id]);
        
        sort(mem[tmp]+1,mem[tmp]+sz+1,cmp1);//heng zuobiao
    
        int le=nc(),ri=nc();
        int sl=0,sr=0;
        for(int i=sz;i>=1;i--){
            mem[ri][++sr]=mem[tmp][i];
        }    
        for(int i=1;i<=sz;i++){
            int now=p[mem[tmp][i]].x;
            while(p[mem[tmp][i]].x==now&&i<=sz){
                mem[le][++sl]=mem[tmp][i];
                mem[ri][sr--]=0;
                i++;
            }
            i--;
            
            if(!(sl&&sr)) continue;
            
            for(int p=1;p<=re-1;p++){
                ret=min(ret,dfs(le,sl,p)+dfs(ri,sr,re-p));
            }
        }
        
        le=nc();ri=nc();
        sl=0;sr=0;
    
        sort(mem[tmp]+1,mem[tmp]+sz+1,cmp2);//zong zuobiao
        
        for(int i=sz;i>=1;i--){
            mem[ri][++sr]=mem[tmp][i];
        }
        for(int i=1;i<=sz;i++){
            int now=p[mem[tmp][i]].y;
            while(p[mem[tmp][i]].y==now&&i<=sz){
                mem[le][++sl]=mem[tmp][i];
                mem[ri][sr--]=0;
                i++;
            }
            i--;
            
            if(!(sr&&sl)) continue;
            
            for(int p=1;p<=re-1;p++){
                ret=min(ret,dfs(le,sl,p)+dfs(ri,sr,re-p));
            }
        }
        
        dele(tmp);dele(le);dele(ri);
        
        return ret;
    }
    int main()
    {
        scanf("%d%d",&n,&k);
        if(n<=k){
            printf("0");return 0;
        }
        
        int st=nc();
        for(int i=1;i<=n;i++){
            scanf("%d%d",&p[i].x,&p[i].y);
            mem[st][i]=i;
        }
        ans=dfs(st,n,k);
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    KVM源代码阅读--内核版本3.17.4
    最新的裸机联想笔记本装win7系统/SSD(固态硬盘)上安装win7系统/联想K4450A i7装win7系统
    Vmaware复制后的虚拟机不能上网问题解决
    KVM基于X86硬件辅助的虚拟化技术实现机制【转】
    KVM和QEMU简介
    笔记--[基于完全虚拟化的安全监控技术研究_张丽(2013)]
    win8预装系统环境下安装win7问题以及双操作系统安装解决
    VM 操作系统实例化(基于 KVM 的虚拟化研究及应用--崔泽永(2011))的论文笔记
    VMware vsphere Hypervisor、VMware vsphere和VMware Workstation小记
    虚拟化、(完)全虚拟化、半虚拟化和准虚拟化技术个人总结
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9571198.html
Copyright © 2011-2022 走看看