noip2002 矩形覆盖
Posted miracevin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; }
以上是关于noip2002 矩形覆盖的主要内容,如果未能解决你的问题,请参考以下文章