【CodeVS1101】【NOIP2002】矩形覆盖

4 篇文章 0 订阅
3 篇文章 0 订阅

【Description】

  在平面上有 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。各个矩形必须完全分开(边线与顶点也都不能重合)。


【Input】

  键盘输人文件名。文件格式为
   n k
   xl y1
   x2 y2
   … …
   xn yn (0<=xi,yi<=500)


【Output】

  输出至屏幕。格式为:
  一个整数,即满足条件的最小的矩形面积之和。


【Sample Input】

4 2
1 1
2 2
3 6
0 7

【Sample Output】

4

【Data Size and Hint】

  k<4
  官方是k<=4,但是标程解法在k=4时是有反例的。官方的数据也没有出现k=4的情况


【Solution】

  数据范围很小,这样搜索便是一个不错的方法。
  
  参考代码如下:

type point =
       record
         x,y:longint;
       end;
     rectangle =
       record
         x1,x2,y1,y2:longint;
       end;
var n,k,ans:longint;
    p:array[1..51] of point;
    a:array[1..3] of rectangle;
function max(x,y:longint):longint;
  begin if x>y then exit(x) else exit(y); end;
function min(x,y:longint):longint;
  begin if x<y then exit(x) else exit(y); end;
procedure init;  //读入初始化
  var i:longint;
  begin
    readln(n,k);
    for i:=1 to n do readln(p[i].x,p[i].y);
    ans:=maxlongint;
    fillchar(a,sizeof(a),255);
  end;
function calc:longint;  //计算矩形面积
  var i:longint;
  begin
    calc:=0;
    for i:=1 to k do
      with a[i] do begin
        if x1=-1 then continue;
        inc(calc,(x2-x1)*(y2-y1));
      end;
  end;
procedure edit(x:point; var r:rectangle);  //修改矩形大小
  begin
    if r.x1=-1 then
      with r do begin
        x1:=x.x; x2:=x.x; y1:=x.y; y2:=x.y;
        exit;
      end;
    if x.x<r.x1 then r.x1:=x.x;
    if x.x>r.x2 then r.x2:=x.x;
    if x.y<r.y1 then r.y1:=x.y;
    if x.y>r.y2 then r.y2:=x.y;
  end;
function intersect(a,b:rectangle):boolean;  //判断两个矩形是否相交
  var x1,x2,y1,y2:longint;
  begin
    x1:=max(a.x1,b.x1);
    x2:=min(a.x2,b.x2);
    y1:=max(a.y1,b.y1);
    y2:=min(a.y2,b.y2);
    intersect:=not((x1>x2) or (y1>y2));
  end;
function judge:boolean; //判断是否存在相交矩形
  var i,j:longint;
  begin
    judge:=true;
    for i:=1 to k do begin
      if a[i].x1=-1 then continue;
      for j:=1 to k do begin
        if a[j].x1=-1 then continue;
        if i=j then continue;
        if intersect(a[i],a[j]) then exit(false);
      end;
    end;
  end;
procedure dfs(dep:longint);  //深度优先搜索
  var i,tmp:longint;
      tmpr:rectangle;
  begin
    tmp:=calc;
    if dep=n+1 then begin
      if tmp<ans then ans:=tmp;
      exit;
    end;
    if tmp>ans then exit;
    for i:=1 to k do begin
      tmpr:=a[i];
      edit(p[dep],a[i]);
      if not judge then begin
        a[i]:=tmpr; continue;
      end;
      dfs(dep+1);
      a[i]:=tmpr;
    end;
  end;
begin
  init;
  dfs(1);
  writeln(ans);
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值