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;
}
原文地址:https://www.cnblogs.com/Miracevin/p/9571198.html