矩形覆盖题解讲解.docx

上传人:b****7 文档编号:23604957 上传时间:2023-05-18 格式:DOCX 页数:32 大小:55.93KB
下载 相关 举报
矩形覆盖题解讲解.docx_第1页
第1页 / 共32页
矩形覆盖题解讲解.docx_第2页
第2页 / 共32页
矩形覆盖题解讲解.docx_第3页
第3页 / 共32页
矩形覆盖题解讲解.docx_第4页
第4页 / 共32页
矩形覆盖题解讲解.docx_第5页
第5页 / 共32页
点击查看更多>>
下载资源
资源描述

矩形覆盖题解讲解.docx

《矩形覆盖题解讲解.docx》由会员分享,可在线阅读,更多相关《矩形覆盖题解讲解.docx(32页珍藏版)》请在冰豆网上搜索。

矩形覆盖题解讲解.docx

矩形覆盖题解讲解

第四题 矩形覆盖

矩形覆盖(存盘名NOIPG4)

[问题描述]:

  在平面上有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。

各个矩形必须完全分开(边线与顶点也都不能重合)。

[输入]:

  键盘输人文件名。

文件格式为

   nk

   xly1

   x2y2

   ......

   xnyn(0<=xi,yi<=500)

[输出]:

  输出至屏幕。

格式为:

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

[输入输出样例]

d.in:

 42

 11

 22

 36

 07

屏幕显示:

4

 

分析

【题解一】

1、本题的难度较大。

如果你这样认为:

即在假定已用i个矩形(面积和满足最小)覆盖所有点的基础上,穷举所有2个矩形合并成1个矩形(条件是:

在所有合并方案中使合并后面积最小),从而使矩形个数减少为i-1——那就错了,可是却可以通过前4组测试数据!

正确的做法是对不同的K值分别进行计算,好在K值较小,否则...

讨论:

k=1,只要求出n个点坐标的最大、最小值,就可求得矩形的位置与面积;

k=2,有2个矩形,它们只有2种分布形式:

左右式(flag=0),上下式(flag=1)

 

对于左右式,显然要先将所有点按横坐标升序排列,可将点1~点i-1放入矩形1中,将点i~点n放入矩形2中,求两矩形的面积之和;如果面积和比上一个值小,记下;让i从2循环到n,就可完成左右式的全部搜索;

对于上下式,先将所有点按纵坐标升序排列,依此类推。

k=3,有3个矩形,它们有6种分布形式:

 

 

要用两重循环进行搜索:

设i,j为循环变量,将点1~i-1放入矩形1中,点i~j-1放入矩形2中,点j~n放入矩形3中;点必须在放入前排好序(均为升序):

对于flag=0,所有点按横坐标排序;对于flag=1,所有点按纵坐标排序;对于flag=2,所有点先按横坐标排序,然后点i~n按纵坐标排序;对于flag=3,所有点先按横坐标排序,然后点1~j-1按纵坐标排序;对于flag=4,所有点先按纵坐标排序,然后点1~j-1按横坐标排序;对于flag=5,所有点先按纵坐标排序,然后点i~n按横坐标排序;

至于k=4,4个矩形有22种分布形式,实在太复杂!

幸好测试数据中没有K=4的情形(似乎有意放了一马?

)。

据说本题全国没有一人全对!

(只要求K=1,2,3)

程序清单

{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q-,R-,S-,T-,V+,X+,Y+}

{$M65520,0,655360}

programNOIPG4;

constmaxn=50;maxk=3;

typerect=record{定义"矩形"数据类型}

l,r,t,b:

word;{矩形的左边,右边,下边,上边距坐标轴的距离}

end;

vxy=record{定义"点"数据类型}

x,y:

word;{点的横、纵坐标}

end;

varju:

array[1..maxk]ofrect;

v:

array[1..maxn,0..2]ofvxy;v0:

vxy;

n,k,i,j,ii,jj:

byte;f:

text;filename:

string;

Smin,temp:

longint;

functionintersect(jui,juj:

rect):

boolean;{判断两矩形是否有公共点}

varb1,b2,t1,t2,l1,l2,r1,r2:

word;

begin

b1:

=jui.b;b2:

=juj.b;t1:

=jui.t;t2:

=juj.t;

l1:

=jui.l;l2:

=juj.l;r1:

=jui.r;r2:

=juj.r;

intersect:

=((l2<=r1)and(l2>=l1)or(r2<=r1)and(r2>=l1)or(l2<=l1)

and(r2>=r1))and((t2<=b1)and(t2>=t1)or(b2<=b1)and(b2>=t1)

or(b2>=b1)and(t2<=t1));

end;

functionarea(ju:

rect):

longint;{求矩形的面积}

vartemp:

longint;

begin

temp:

=ju.b-ju.t;area:

=temp*(ju.r-ju.l);

{不能直接写成area:

=(ju.b-ju.t)*(ju.r-ju.l);因为这样可能会溢出!

}

end;

procedureinsert(v:

vxy;varju:

rect);{将点放入矩形}

begin

ifv.x

=v.x;

ifv.x>ju.rthenju.r:

=v.x;

ifv.y

=v.y;

ifv.y>ju.bthenju.b:

=v.y;

end;

procedureinit;{初始化}

begin

write('Inputfilename:

');readln(filename);

assign(f,filename);reset(f);readln(f,n,k);

fori:

=1tondobegin

read(f,v[i,0].x,v[i,0].y);

v[i,1].x:

=v[i,0].x;v[i,1].y:

=v[i,0].y;

end;

fori:

=1ton-1do{按横坐标升序排列各点,存入v[i,0]}

forj:

=i+1tondo

ifv[i,0].x>v[j,0].xthenbegin

v0:

=v[i,0];v[i,0]:

=v[j,0];v[j,0]:

=v0;

end;

fori:

=1ton-1do{按纵坐标升序排列各点,存入v[i,1]}

forj:

=i+1tondo

ifv[i,1].y>v[j,1].ythenbegin

v0:

=v[i,1];v[i,1]:

=v[j,1];v[j,1]:

=v0;

end;

end;

proceduresolve;{核心计算}

begin

smin:

=maxlongint;

casekof

1:

begin{K=1的情形}

ju[1].b:

=v[n,1].y;ju[1].t:

=v[1,1].y;

ju[1].r:

=v[n,0].x;ju[1].l:

=v[1,0].x;

smin:

=area(ju[1]);

end;

2:

forjj:

=0to1dobegin{K=2的情形}

{flag=0,1的情形}

ju[1].b:

=v[1,jj].y;ju[1].t:

=v[1,jj].y;

ju[1].r:

=v[1,jj].x;ju[1].l:

=v[1,jj].x;

fori:

=2tondobegin

insert(v[i-1,jj],ju[1]);{将第i-1点放入矩形1}

ju[2].b:

=v[i,jj].y;ju[2].t:

=v[i,jj].y;{将第i至n点放入矩形2}

ju[2].r:

=v[i,jj].x;ju[2].l:

=v[i,jj].x;

forii:

=i+1tondoinsert(v[ii,jj],ju[2]);

ifnotintersect(ju[1],ju[2])thenbegin{如果两矩形不交叉}

temp:

=0;forii:

=1tokdotemp:

=temp+area(ju[ii]);

iftemp

=temp;

end;

end;

end;

3:

begin

forjj:

=0to1dobegin{flag=0,1的情形}

ju[1].b:

=v[1,jj].y;ju[1].t:

=v[1,jj].y;

ju[1].r:

=v[1,jj].x;ju[1].l:

=v[1,jj].x;

fori:

=2ton-1dobegin

insert(v[i-1,jj],ju[1]);

ju[2].b:

=v[i,jj].y;ju[2].t:

=v[i,jj].y;

ju[2].r:

=v[i,jj].x;ju[2].l:

=v[i,jj].x;

ifintersect(ju[1],ju[2])thencontinue;

forj:

=i+1tondobegin

insert(v[j-1,jj],ju[2]);

ju[3].b:

=v[j,jj].y;ju[3].t:

=v[j,jj].y;

ju[3].r:

=v[j,jj].x;ju[3].l:

=v[j,jj].x;

forii:

=j+1tondoinsert(v[ii,jj],ju[3]);

ifintersect(ju[2],ju[3])thencontinue;

temp:

=0;forii:

=1tokdotemp:

=temp+area(ju[ii]);

iftemp

=temp;

end;

end;

end;

{flag=2的情形:

先竖直划分大矩形;再在右矩形中水平划分}

ju[1].b:

=v[1,0].y;ju[1].t:

=v[1,0].y;

ju[1].r:

=v[1,0].x;ju[1].l:

=v[1,0].x;

fori:

=2ton-1dobegin

forii:

=1tondov[ii,2]:

=v[ii,0];{所有点按横坐标升序排列,存入v[i,2]}

forii:

=iton-1do{将点i至n按纵坐标升序排列,存入v[i,2]}

forjj:

=ii+1tondo

ifv[ii,2].y>v[jj,2].ythenbegin

v0:

=v[ii,2];v[ii,2]:

=v[jj,2];v[jj,2]:

=v0;

end;{结果:

所有点先按横坐标升序排列,然后点i至n按纵坐标升序排列}

insert(v[i-1,2],ju[1]);{将第i-1点放入矩形1}

ju[2].b:

=v[i,2].y;ju[2].t:

=v[i,2].y;{将第i点放入矩形2}

ju[2].r:

=v[i,2].x;ju[2].l:

=v[i,2].x;

ifintersect(ju[1],ju[2])thencontinue;

forj:

=i+1tondobegin

insert(v[j-1,2],ju[2]);{将第j-1点放入矩形2}

ju[3].b:

=v[j,2].y;ju[3].t:

=v[j,2].y;{将第j至n点放入矩形3}

ju[3].r:

=v[j,2].x;ju[3].l:

=v[j,2].x;

forii:

=j+1tondoinsert(v[ii,2],ju[3]);

ifintersect(ju[2],ju[3])thencontinue;

temp:

=0;forii:

=1tokdotemp:

=temp+area(ju[ii]);

iftemp

=temp;

end;

end;

{flag=3的情形}

forj:

=3tondobegin

forii:

=1tondov[ii,2]:

=v[ii,0];

forii:

=1toj-2do

forjj:

=ii+1toj-1do

ifv[ii,2].y>v[jj,2].ythenbegin

v0:

=v[ii,2];v[ii,2]:

=v[jj,2];v[jj,2]:

=v0;

end;

ju[3].b:

=v[j,2].y;ju[3].t:

=v[j,2].y;

ju[3].r:

=v[j,2].x;ju[3].l:

=v[j,2].x;

forii:

=j+1tondoinsert(v[ii,2],ju[3]);

fori:

=2toj-1dobegin

ju[2].b:

=v[i,2].y;ju[2].t:

=v[i,2].y;

ju[2].r:

=v[i,2].x;ju[2].l:

=v[i,2].x;

forii:

=i+1toj-1doinsert(v[ii,2],ju[2]);

ju[1].b:

=v[1,2].y;ju[1].t:

=v[1,2].y;

ju[1].r:

=v[1,2].x;ju[1].l:

=v[1,2].x;

forii:

=2toi-1doinsert(v[ii,2],ju[1]);

ifintersect(ju[1],ju[2])orintersect(ju[2],ju[3])or

intersect(ju[1],ju[3])thencontinue;

temp:

=0;forii:

=1tokdotemp:

=temp+area(ju[ii]);

iftemp

=temp;

end;

end;

{flag=4的情形}

forj:

=3tondobegin

forii:

=1tondov[ii,2]:

=v[ii,1];

forii:

=1toj-2do

forjj:

=ii+1toj-1do

ifv[ii,2].x>v[jj,2].xthenbegin

v0:

=v[ii,2];v[ii,2]:

=v[jj,2];v[jj,2]:

=v0;

end;

ju[3].b:

=v[j,2].y;ju[3].t:

=v[j,2].y;

ju[3].r:

=v[j,2].x;ju[3].l:

=v[j,2].x;

forii:

=j+1tondoinsert(v[ii,2],ju[3]);

fori:

=2toj-1dobegin

ju[2].b:

=v[i,2].y;ju[2].t:

=v[i,2].y;

ju[2].r:

=v[i,2].x;ju[2].l:

=v[i,2].x;

forii:

=i+1toj-1doinsert(v[ii,2],ju[2]);

ju[1].b:

=v[1,2].y;ju[1].t:

=v[1,2].y;

ju[1].r:

=v[1,2].x;ju[1].l:

=v[1,2].x;

forii:

=2toi-1doinsert(v[ii,2],ju[1]);

ifintersect(ju[1],ju[2])orintersect(ju[2],ju[3])or

intersect(ju[1],ju[3])thencontinue;

temp:

=0;forii:

=1tokdotemp:

=temp+area(ju[ii]);

iftemp

=temp;

end;

end;

{flag=5的情形}

ju[1].b:

=v[1,1].y;ju[1].t:

=v[1,1].y;

ju[1].r:

=v[1,1].x;ju[1].l:

=v[1,1].x;

fori:

=2ton-1dobegin

forii:

=1tondov[ii,2]:

=v[ii,1];

forii:

=iton-1do

forjj:

=ii+1tondo

ifv[ii,2].x>v[jj,2].xthenbegin

v0:

=v[ii,2];v[ii,2]:

=v[jj,2];v[jj,2]:

=v0;

end;

insert(v[i-1,2],ju[1]);

ju[2].b:

=v[i,2].y;ju[2].t:

=v[i,2].y;

ju[2].r:

=v[i,2].x;ju[2].l:

=v[i,2].x;

ifintersect(ju[1],ju[2])thencontinue;

forj:

=i+1tondobegin

insert(v[j-1,2],ju[2]);

ju[3].b:

=v[j,2].y;ju[3].t:

=v[j,2].y;

ju[3].r:

=v[j,2].x;ju[3].l:

=v[j,2].x;

forii:

=j+1tondoinsert(v[ii,2],ju[3]);

ifintersect(ju[2],ju[3])thencontinue;

temp:

=0;forii:

=1tokdotemp:

=temp+area(ju[ii]);

iftemp

=temp;

end;

end;

end;

end;

end;

begin{主程序}

init;

solve;

writeln(smin);

end.

点评:

压轴题据说,本次复赛主要是前三题的竞争,可见本题能得分的人相当少,但是K=1应该说是送分的,K=2也是比较容易的。

通过测试,发现在K=3的第4、5组测试数据中仅用到了flag=1的情形,也就是说,只要写出flag=1的程序段就OK了(没写flag=0,2,3,4,5的同学偷着乐?

)。

【题解二】

具体方法是将每个点极角排序然后就是一个经典的DP了:

f[i,j,k]=min(f[i,j,k],f[i,t,k-1]+s[t+1,j])

另外注意要DP两次因为可以是横着的也可以是竖着的

具体实现参见以下代码:

var

  n,m,i,t,ans,last:

longint;

  x,y:

array[1..51]ofinteger;

proceduresort(l,r:

integer);

var

  i,j,mid,t:

integer;

begin

  i:

=l;j:

=r;mid:

=x[(l+r)shr1];

  repeat

    while(x[i]

    while(x[j]>mid)dodec(j);

    ifi<=jthen

      begin

        t:

=x[i];x[i]:

=x[j];x[j]:

=t;

        t:

=y[i];y[i]:

=y[j];y[j]:

=t;

              inc(i);dec(j);

      end;

  untili>j;

  ifi

  ifl

end;

procedureqsort(l,r:

integer);

var

  i,j,mid,t:

integer;

begin

  i:

=l;j:

=r;mid:

=y[(l+r)shr1];

  repeat

    while(y[i]

    while(y[j]>mid)dodec(j);

    ifi<=jthen

      begin

        t:

=x[i];x[i]:

=x[j];x[j]:

=t;

        t:

=y[i];y[i]:

=y[j];y[j]:

=t;

              inc(i);dec(j);

      end;

  untili>j;

  ifi

  ifl

end;

functionhight(l,r:

integer):

integer;

var

  i,smax,smin:

integer;

begin

  smax:

=0;smin:

=maxint;

  fori:

=ltordo

    begin

      ify[i]>smaxthensmax:

=y[i];

      ify[i]

=y[i];

    end;

  hight:

=smax-smin;

end;

functionmin(x,y:

longint):

longint;

begin

  ifx

=xelsemin:

=y;

end;

procedureDynamic;

var

  j,k,p:

integer;

  s:

array[1..50,1..50]oflongint;

  f:

array[1..50,1..50,1..4]oflongint;

begin

  fori:

=1tomdo

    forj:

=1tomdo

      fork:

=1tondo

        f[i,j,k]:

=300000;

  fori:

=1tomdo

    forj:

=itomdo

      begin

        s[i,j]:

=(x[j]-x[i])*hight(i,j);

        f[i,j,1]:

=s[i,j];

      end;

  forp:

=1tomdo

    fori:

=1tom-pdo

      begin

        j:

=i+p;

        fork:

=2tondo

          fort:

=itoj-1do

            f[i,j,k]:

=min(f[i,j,k],f[i,t,k-1]+s[t+1,j]);

      end;

  ans:

=min(ans,f[1,m,n]);

end;

begin

  assign(input,'t4.in');reset(input);

  assign(output,'t4.out');rewrite(output);

  readln(m,n);

  fori:

=1tomdo

    readln(x[i],y[i]);

  x[m+1]:

=maxint;y[m+1]:

=maxint;

  ans:

=maxlongint;

  sort(1,m);

  t:

=x[1];last:

=1;

  fori:

=2tom+1do

    ifx[i]<>tthen

      begin

        qsort(last,i-1);

        t:

=x[i];

        last:

=i;

      end;

  Dynamic;

  

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 外语学习 > 英语学习

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1