第四题 矩形覆盖
矩形覆盖(存盘名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。各个矩形必须完全分开(边线与顶点也都不能重合)。
[输入]: 键盘输人文件名。文件格式为 n k xl y1 x2 y2 ... ... xn yn (0<=xi,yi<=500)
[输出]: 输出至屏幕。格式为: 一个整数,即满足条件的最小的矩形面积之和。
[输入输出样例]d.in : 4 2 1 1 2 2 3 6 0 7屏幕显示: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+}
{$M 65520,0,655360}
program NOIPG4;
const maxn=50;maxk=3;
type rect=record{定义"矩形"数据类型}
l,r,t,b:word;{矩形的左边,右边,下边,上边距坐标轴的距离}
end;
vxy=record{定义"点"数据类型}
x,y:word;{点的横、纵坐标}
end;
var ju:array[1..maxk]of rect;
v:array[1..maxn,0..2] of vxy;v0:vxy;
n,k,i,j,ii,jj:byte;f:text;filename:string;
Smin,temp:longint;
function intersect(jui,juj:rect):boolean;{判断两矩形是否有公共点}
var b1,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;
function area(ju:rect):longint;{求矩形的面积}
var temp:longint;
begin
temp:=ju.b-ju.t;area:=temp*(ju.r-ju.l);
{不能直接写成area:=(ju.b-ju.t)*(ju.r-ju.l);因为这样可能会溢出!}
end;
procedure insert(v:vxy;var ju:rect);{将点放入矩形}
begin
if v.x
if v.x>ju.r then ju.r:=v.x;
if v.y
if v.y>ju.b then ju.b:=v.y;
end;
procedure init;{初始化}
begin
write('Input filename:');readln(filename);
assign(f,filename);reset(f);readln(f,n,k);
for i:=1 to n do begin
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;
for i:=1 to n-1 do{按横坐标升序排列各点,存入v[i,0]}
for j:=i+1 to n do
if v[i,0].x>v[j,0].x then begin
v0:=v[i,0];v[i,0]:=v[j,0];v[j,0]:=v0;
end;
for i:=1 to n-1 do{按纵坐标升序排列各点,存入v[i,1]}
for j:=i+1 to n do
if v[i,1].y>v[j,1].y then begin
v0:=v[i,1];v[i,1]:=v[j,1];v[j,1]:=v0;
end;
end;
procedure solve;{核心计算}
begin
smin:=maxlongint;
case k of
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:for jj:=0 to 1 do begin{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;
for i:=2 to n do begin
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;
for ii:=i+1 to n do insert(v[ii,jj],ju[2]);
if not intersect(ju[1],ju[2]) then begin{如果两矩形不交叉}
temp:=0;for ii:=1 to k do temp:=temp+area(ju[ii]);
if temp
end;
end;
end;
3:begin
for jj:=0 to 1 do begin {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;
for i:=2 to n-1 do begin
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;
if intersect(ju[1],ju[2]) then continue;
for j:=i+1 to n do begin
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;
for ii:=j+1 to n do insert(v[ii,jj],ju[3]);
if intersect(ju[2],ju[3]) then continue;
temp:=0;for ii:=1 to k do temp:=temp+area(ju[ii]);
if 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;
for i:=2 to n-1 do begin
for ii:=1 to n do v[ii,2]:=v[ii,0];{所有点按横坐标升序排列,存入v[i,2]}
for ii:=i to n-1 do{将点i至n按纵坐标升序排列,存入v[i,2]}
for jj:=ii+1 to n do
if v[ii,2].y>v[jj,2].y then begin
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;
if intersect(ju[1],ju[2]) then continue;
for j:=i+1 to n do begin
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;
for ii:=j+1 to n do insert(v[ii,2],ju[3]);
if intersect(ju[2],ju[3]) then continue;
temp:=0;for ii:=1 to k do temp:=temp+area(ju[ii]);
if temp
end;
end;
{flag=3的情形}
for j:=3 to n do begin
for ii:=1 to n do v[ii,2]:=v[ii,0];
for ii:=1 to j-2 do
for jj:=ii+1 to j-1 do
if v[ii,2].y>v[jj,2].y then begin
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;
for ii:=j+1 to n do insert(v[ii,2],ju[3]);
for i:=2 to j-1 do begin
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;
for ii:=i+1 to j-1 do insert(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;
for ii:=2 to i-1 do insert(v[ii,2],ju[1]);
if intersect(ju[1],ju[2]) or intersect(ju[2],ju[3]) or
intersect(ju[1],ju[3]) then continue;
temp:=0;for ii:=1 to k do temp:=temp+area(ju[ii]);
if temp
end;
end;
{flag=4的情形}
for j:=3 to n do begin
for ii:=1 to n do v[ii,2]:=v[ii,1];
for ii:=1 to j-2 do
for jj:=ii+1 to j-1 do
if v[ii,2].x>v[jj,2].x then begin
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;
for ii:=j+1 to n do insert(v[ii,2],ju[3]);
for i:=2 to j-1 do begin
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;
for ii:=i+1 to j-1 do insert(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;
for ii:=2 to i-1 do insert(v[ii,2],ju[1]);
if intersect(ju[1],ju[2]) or intersect(ju[2],ju[3]) or
intersect(ju[1],ju[3]) then continue;
temp:=0;for ii:=1 to k do temp:=temp+area(ju[ii]);
if 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;
for i:=2 to n-1 do begin
for ii:=1 to n do v[ii,2]:=v[ii,1];
for ii:=i to n-1 do
for jj:=ii+1 to n do
if v[ii,2].x>v[jj,2].x then begin
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;
if intersect(ju[1],ju[2]) then continue;
for j:=i+1 to n do begin
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;
for ii:=j+1 to n do insert(v[ii,2],ju[3]);
if intersect(ju[2],ju[3]) then continue;
temp:=0;for ii:=1 to k do temp:=temp+area(ju[ii]);
if 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] of integer;procedure sort(l,r:integer);var i,j,mid,t:integer;begin i:=l;j:=r;mid:=x[(l+r) shr 1]; repeat while(x[i]
【题解三】
好吧,我承认,此题真正地震撼了我,我无语。。。
K明明是1到4的取值,由于数据最大K为3,然后所有的做法竟然都是分情况模拟!K=1时如何,K=2时有哪些分的情况。。。(上下分,左右分),K=3的时候6种情况。
每次都要排序X,Y坐标,算面积。
{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P-,Q-,R-,S-,T-,V+,X+,Y+}{$M 65520,0,655360}program NOIPG4;const maxn=50;maxk=3;type rect=record{定义"矩形"数据类型} l,r,t,b:word;{矩形的左边,右边,下边,上边距坐标轴的距离} end; vxy=record{定义"点"数据类型} x,y:word;{点的横、纵坐标} end;var ju:array[1..maxk]of rect; v:array[1..maxn,0..2] of vxy;v0:vxy; n,k,i,j,ii,jj:byte;f:text;filename:string; Smin,temp:longint;function intersect(jui,juj:rect):boolean;{判断两矩形是否有公共点} var b1,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;function area(ju:rect):longint;{求矩形的面积} var temp:longint; begin temp:=ju.b-ju.t; area:=temp*(ju.r-ju.l); end;procedure insert(v:vxy;var ju:rect);{将点放入矩形} begin if v.x
{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; for i:=2 to n-1 do begin for ii:=1 to n do v[ii,2]:=v[ii,0];{所有点按横坐标升序排列,存入v[i,2]} for ii:=i to n-1 do{将点i至n按纵坐标升序排列,存入v[i,2]} for jj:=ii+1 to n do if v[ii,2].y>v[jj,2].y then begin 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; if intersect(ju[1],ju[2]) then continue; for j:=i+1 to n do begin 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; for ii:=j+1 to n do insert(v[ii,2],ju[3]); if intersect(ju[2],ju[3]) then continue; temp:=0;for ii:=1 to k do temp:=temp+area(ju[ii]); if temp
{flag=3的情形} for j:=3 to n do begin for ii:=1 to n do v[ii,2]:=v[ii,0]; for ii:=1 to j-2 do for jj:=ii+1 to j-1 do if v[ii,2].y>v[jj,2].y then begin 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; for ii:=j+1 to n do insert(v[ii,2],ju[3]); for i:=2 to j-1 do begin 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; for ii:=i+1 to j-1 do insert(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; for ii:=2 to i-1 do insert(v[ii,2],ju[1]); if intersect(ju[1],ju[2]) or intersect(ju[2],ju[3]) or intersect(ju[1],ju[3]) then continue; temp:=0;for ii:=1 to k do temp:=temp+area(ju[ii]); if temp
{flag=4的情形} for j:=3 to n do begin for ii:=1 to n do v[ii,2]:=v[ii,1]; for ii:=1 to j-2 do for jj:=ii+1 to j-1 do if v[ii,2].x>v[jj,2].x then begin 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; for ii:=j+1 to n do insert(v[ii,2],ju[3]); for i:=2 to j-1 do begin 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; for ii:=i+1 to j-1 do insert(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; for ii:=2 to i-1 do insert(v[ii,2],ju[1]); if intersect(ju[1],ju[2]) or intersect(ju[2],ju[3]) or intersect(ju[1],ju[3]) then continue; temp:=0;for ii:=1 to k do temp:=temp+area(ju[ii]); if temp
{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; for i:=2 to n-1 do begin for ii:=1 to n do v[ii,2]:=v[ii,1]; for ii:=i to n-1 do for jj:=ii+1 to n do if v[ii,2].x>v[jj,2].x then begin 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; if intersect(ju[1],ju[2]) then continue; for j:=i+1 to n do begin 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; for ii:=j+1 to n do insert(v[ii,2],ju[3]); if intersect(ju[2],ju[3]) then continue; temp:=0;for ii:=1 to k do temp:=temp+area(ju[ii]); if temp
【题解四】
各种剪枝优化。。。
//By LYLtim
uses math;
type rnode=record xl,xr,yu,yd:integer; end;
var n,k:byte; ans:longword; v:array[1..50]of record x,y:integer; end; rect:array[1..4]of rnode;
procedure init;var i:byte;begin readln(n,k); for i:=1 to n do with v[i] do readln(x,y); for i:=1 to k do with rect[i] do begin xl:=501;xr:=-1;yu:=-1;yd:=501; end; ans:=1000000;end;{init}
procedure search(dep:byte);var i,j:byte; s:longword; tmp:rnode;begin s:=0; for i:=1 to k do if rect[i].xl<501 then begin inc(s,(rect[i].xr-rect[i].xl)*(rect[i].yu-rect[i].yd)); if s>=ans then exit; for j:=i+1 to k do if(rect[j].xl<501)and(rect[j].yd<=rect[i].yu)and (rect[j].yu>=rect[i].yd)and(rect[j].xr>=rect[i].xl) and(rect[j].xl<=rect[i].xr)then exit; //两个矩形相交就跳出 end; if dep>n then begin ans:=s; exit; end; for i:=1 to k do begin tmp:=rect[i]; rect[i].xl:=min(rect[i].xl,v[dep].x); rect[i].xr:=max(rect[i].xr,v[dep].x); rect[i].yu:=max(rect[i].yu,v[dep].y); rect[i].yd:=min(rect[i].yd,v[dep].y); search(dep+1); rect[i]:=tmp; end;end;{search}
begin{main} init; search(1); writeln(ans);end.
【题解五】
因为矩形最多是4个,所以简单搜索每个点属于哪个矩形即可。注意条件里写矩形间两两不相交。var b:array[1..4,1..4]of longint; x,y:array[1..50]of longint; n,k,i,ans:longint;procedure qsort(l,r:longint);var i,j,midx,midy,temp:longint;begin i:=l;j:=r;midx:=x[(l+r)shr 1];midy:=y[(l+r)shr 1]; while i
【问题分析】
由于k的取值只有四种情况,所以我采用对k分类讨论的办法。
k=1时,很简单,不说了。
k=2时,将所有点按横坐标排序,用一条平行与y轴的直线将所有点分为两部分,分别用一个矩形覆盖,可得到一个解。枚举所有这样的划分方案进行求解(即对点进行枚举,用每个点及其后一个点之间的直线划分)。再按纵坐标排序,用平行与x轴的直线划分,同样方法求解。最后得到最优解。
k=3时,类似于k=2时的情况。只是划分后,一部分用一个矩形覆盖,另一部分用两个矩形覆盖,并求解。然后颠倒过来再求解。
k=4时,简单地用直线划分不一定能求得最优解(如右图,其最优解是零)。我的算法是枚举每个点,将它以及它左下方(包括正左方和正下方)的点用一个矩形覆盖,而其余的点用三个矩形覆盖。这个算法有一个缺陷,即有可能违背“各个矩形必须完全分开”的限制条件,而得到比实际最优解更小的结果。但对于绝大部分数据是没有问题的。另外,对于绝大部分随机生成的数据,甚至直接用直线划分也可求得最优解。
【程序清单】
{$A+,B-,D+,E+,F-,G-,I-,L+,N-,O-,P-,Q-,R-,S-,T-,V+,X+}
{$M 16384,0,655360}
Program NOIPG4;
Type
SetType=[1..50,1..2] Of LongInt;
Var
Infile:Text;
InName:String;
N,K:LongInt;
Data:SetType;{存储所有的点}
i:LongInt;
Function Solve1(Var CurSet:SetType;A,B:Integer):LongInt;
{用一个矩形覆盖CurSet中的第A个点到第B个点}
Var
i:LongInt;
Up,Down,Left,Right:LongInt;
{分别为最大纵坐标、最小纵坐标、最小横坐标、最大横坐标}
Begin
If B-A+1<=1 Then
Begin
Solve1:=0;
Exit;
End;
Up:=0;
Down:=500;
Left:=500;
Right:=0;
For i:=A To B Do
Begin
If CurSet[i,1]
If CurSet[i,1]>Right Then Right:=CurSet[i,1];
If CurSet[i,2]
If CurSet[i,2]>Up Then Up:=CurSet[i,2];
End;
Solve1:=(Up-Down)*(Right-Left);
End;{Solve1}
Function Solve2(CurSet:SetType;A,B:Integer):LongInt;
{用两个矩形覆盖CurSet中的第A个点到第B个点}
Var
i,j,X,Y,Best,q:LongInt;
Begin
If B-A+1<=2 Then
Begin{只有或不到两个点}
Solve2:=0;
Exit;
End;
Best:=MaxLongInt;
For i:=A To B-1 Do{以横坐标排序(冒泡排序)}
For j:=i+1 To B Do
If CurSet[i,1]>CurSet[j,1] Then
Begin
X:=CurSet[i,1]; Y:=CurSet[i,2];
CurSet[i]:=CurSet[j];
CurSet[j,1]:=X; CurSet[j,2]:=Y;
End;
For i:=A To B-1 Do
Begin
If CurSet[i,1]=CurSet[i+1,1] Then Continue;
{第i个点与第(i+1)个点横坐标相同,不能在它们之间划分}
q:=Solve1(CurSet,A,i)+Solve1(CurSet,i+1,B);
If Best>q Then Best:=q;
End;
For i:=A To B-1 Do{按纵坐标排序}
For j:=i+1 To B Do
If CurSet[i,2]>CurSet[j,2] Then
Begin
X:=CurSet[i,1]; Y:=CurSet[i,2];
CurSet[i]:=CurSet[j];
CurSet[j,1]:=X; CurSet[j,2]:=Y;
End;
For i:=A To B-1 Do
Begin
If CurSet[i,2]=CurSet[i+1,2] Then Continue;
q:=Solve1(CurSet,A,i)+Solve1(CurSet,i+1,B);
If Best>q Then Best:=q;
End;
Solve2:=Best;
End;{Solve2}
Function Solve3(CurSet:SetType;A,B:Integer):LongInt;
{用三个矩形覆盖CurSet中的第A个点到第B个点,类似于Solve2}
Var
i,j,X,Y,Best,q:LongInt;
Begin
If B-A+1<=3 Then
Begin
Solve3:=0;
Exit;
End;
Best:=MaxLongInt;
For i:=A To B-1 Do
For j:=i+1 To B Do
If CurSet[i,1]>CurSet[j,1] Then
Begin
X:=CurSet[i,1]; Y:=CurSet[i,2];
CurSet[i]:=CurSet[j];
CurSet[j,1]:=X; CurSet[j,2]:=Y;
End;
For i:=A To B-1 Do
Begin
If CurSet[i,1]=CurSet[i+1,1] Then Continue;
{直线一边用一个矩形覆盖,另一边用两个矩形覆盖}
q:=Solve1(CurSet,A,i)+Solve2(CurSet,i+1,B);
If Best>q Then Best:=q;
q:=Solve2(CurSet,A,i)+Solve1(CurSet,i+1,B);
If Best>q Then Best:=q;
End;
For i:=A To B-1 Do
For j:=i+1 To B Do
If CurSet[i,2]>CurSet[j,2] Then
Begin
X:=CurSet[i,1]; Y:=CurSet[i,2];
CurSet[i]:=CurSet[j];
CurSet[j,1]:=X; CurSet[j,2]:=Y;
End;
For i:=A To B-1 Do
Begin
If CurSet[i,2]=CurSet[i+1,2] Then Continue;
q:=Solve1(CurSet,A,i)+Solve2(CurSet,i+1,B);
If Best>q Then Best:=q;
q:=Solve2(CurSet,A,i)+Solve1(CurSet,i+1,B);
If Best>q Then Best:=q;
End;
Solve3:=Best;
End;{Solve3}
Function Solve4(CurSet:SetType;A,B:Integer):LongInt;
{用四个矩形覆盖CurSet中的第A个点到第B个点}
Var
i,j,X,Y,Best,q,P1,P2:LongInt;
Set1,Set2:SetType;
Begin
If B-A+1<=4 Then
Begin
Solve4:=0;
Exit;
End;
Best:=MaxLongInt;
For i:=A To B Do{枚举每个点}
Begin
{将第i个点及其左下方(包括正左方和正下方)的点置于Set1中,其余的点置于Set2中}
X:=Data[i,1]; Y:=Data[i,2];
P1:=0; P2:=0;
For j:=A To B Do
If (Data[j,1]<=X) And (Data[j,2]<=Y) Then
Begin
Inc(P1);
Set1[P1]:=Data[j];
End
Else Begin
Inc(P2);
Set2[P2]:=Data[j];
End;
q:=Solve1(Set1,1,P1)+Solve3(Set2,1,P2);
{用一个矩形覆盖Set1中的点,用三个矩形覆盖Set2中的点}
If Best>q Then Best:=q;
End;
Solve4:=Best;
End;{Solve4}
Begin
ReadLn(InName);
Assign(InFile,InName);
Reset(InFile);
ReadLn(InFile,N,K);
For i:=1 To N Do
ReadLn(InFile,Data[i,1],Data[i,2]);
Close(InFile);
Case k Of{分类讨论}
1:
Begin
WriteLn(Solve1(Data,1,N));
End;
2:
Begin
WriteLn(Solve2(Data,1,N));
End;
3:
Begin
WriteLn(Solve3(Data,1,N));
End;
4:
Begin
WriteLn(Solve4(Data,1,N));
End;
End;
End.
¥29.8
¥9.9
¥59.8