POJ 2836:Rectangular Covering(状态压缩DP)

题目大意:在一个平面内有若干个点,要求用一些矩形覆盖它们,一个矩形至少覆盖两个点,可以相互重叠,求矩形最小总面积。

分析:

  数据很小,很容易想到状压DP,我们把点是否被覆盖用0,1表示然后放在一起得到一个最多15位的二进制数字作为状态,对于每种状态枚举矩形,进行覆盖。

  要进行一个预处理,将每种矩形多覆盖的点状态保存下来,并计算面积,然后就是DP了。

  状态转移方程f[s2]=min(f[s2],f[s1]+area) s1为原来状态,s2表示后来放置矩形后的状态。

  因为可以重复覆盖,计算s2不是s2=s1+a[i](a[i]为i矩形的覆盖状态),而是s2=s1 or a[i],因为用或运算,我们不能采取常用的枚举覆盖后状态,推出覆盖前状态这样进行DP,因为一个该矩形i覆盖后的状态可能对应多个原始状态(因为or),所以要枚举初始状态,再计算后来状态求解。

  最后要注意当两个点在同一条平行于坐标轴的直线上时,它们对应的矩形长或宽为1.

代码:

program Rec;
var
  f:array[0..32768]of longint;
  x,y:array[0..15]of longint;
  a,s:array[0..225]of longint;
  n,i,m,num,j,k:longint;
function max(x,y:longint):longint;
begin
  if x>y then max:=x else max:=y;
end;
function min(x,y:longint):longint;
begin
  if x<y then min:=x else min:=y;
end;
procedure workfirst;
var i,j:longint;
begin
  m:=0;
  fillchar(a,sizeof(a),0); fillchar(s,sizeof(s),0);
  num:=1 shl n-1;
  for i:=0 to num do f[i]:=maxlongint;
  f[0]:=0;
end;
procedure workread;
var i,j,k,maxx,minx,maxy,miny:longint;
begin
  for i:=1 to n do readln(x[i],y[i]);
  for i:=2 to n do
   for j:=1 to i-1 do
     begin
      maxx:=max(x[i],x[j]); maxy:=max(y[i],y[j]);
      minx:=min(x[i],x[j]); miny:=min(y[i],y[j]);    inc(m);
      for k:=1 to n do
       if (x[k]>=minx)and(x[k]<=maxx)and(y[k]>=miny)and(y[k]<=maxy) then
         inc(a[m],1 shl (k-1));
      s[m]:=max(1,(maxx-minx))*max(1,(maxy-miny));
     end;
end;
procedure workdp;
var i,j,k:longint;
begin
  for i:=0 to num do
  if  f[i]<>maxlongint then
   for j:=1 to m do
    if i<>a[j] then f[i or a[j]]:=min(f[i or a[j]],f[i]+s[j]);
end;
begin
  assign(input,'Rec.in');
  reset(input);
  assign(output,'Rec.out');
  rewrite(output);
  readln(n);
  while n<>0 do
  begin
    workfirst;
    workread;
    workdp;
    writeln(f[num]);
    readln(n);
  end;
  close(input); close(output);
end.
View Code

 

转载于:https://www.cnblogs.com/qtyytq/p/5303087.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值