愚蠢的村庄

 

背景
Stupid家族的成员们生活在一个名为Stupid的村庄。
话说村里的人要喝水都得到很远很远的另一个Genius村庄打水,这并不算什么,因为Stupid村庄的村民都很勤劳不怕苦。最郁闷的是Genius村庄的村民总是无端BS我们的村民,老是问一些“1+1等于多少”的问题,害得我们答不上来。于是hyc提出要在我们自己村里建一口水井。抛开受BS的日子。

描述
Stupid村庄的村民是愚蠢的,这个村庄也是愚蠢的,他们不知道如何布置自己的村庄,所以村庄的结构很简单。我们设整个村庄处在一个坐标系的第一象限。
而在Stupid村庄里有N座房子,这房子也是愚蠢的。它很扁,可以近似得看做一条直线;它还是平行于坐标轴的(Stupid村民是迷信的…方方正正才是美…)。
现在,要在村里建一水井,我们要使所有房子到水井的距离和最短。
设某一房子的两端点分别为(1,3),(3,3)。若水井的横坐标1〈=x〈=3, 则水井到房子的距离为 abs(水井纵坐标-1),即图中L1,否则(x〈 1 或 x 〉3),距离为min{水井到左端点的距离,水井到右端点的距离},即图中L2。换句话说,让村民们来打水所走的距离和最短。

输入格式

输入文件village.in的第一行为一个正整数N(N〈=100)。
接下来N行输入N座房子的信息,每行为四个非负整数,分别表示房子两端点的坐标。
房子的所有坐标都为0到100间的非负整数。

输出格式

输出文件village.out有且仅有一行,为所求的最短距离(保留两位小数)。

样例输入

样例输出

///

       这道题,乍一看,水题!直接枚举井的位置,100*100,爆了是你人品不好~_~。。。。

       结果事实证明,这只能过5个点。。。。。。

       然后,某位神牛说:“

      事实证明只搜整点与正确结果相差很大,那么,要考虑实点。注意到输出只要求保留两位,我们再搜过整点之后,答案所需的实点就在最优的整点附近。,所以我们可以先枚举依次整点,取前K优的整点(事实证明:取K=6,可以AC),再搜索这些点附近的实点(小数点后一位),就可以得到一个近似最优解(显然这不是完全最优,但对于保留小数足够了。)”

    参考程序如下:

type list=record
      i,j:longint;
      num:real;
     end;
var sum,ans,summ:real;
    n,i,c,d,j,k,maxx,minn,m,x,y,lx,ly:longint;
    zx,zy,yx,yy:array[1..200] of longint;
    a:array[0..10000] of list;//记录每一个“井”的坐标、路径值
function max(a,b:longint):longint;
  begin
    if a>b then max:=a else max:=b;
  end;
function min(a,b:real):real;
  begin
    if a>b then min:=b else min:=a;
  end;
procedure qsort(l,r:longint);
  var m:real;i,j,k:longint;
    begin
      k:=(l+r) div 2;
      i:=l;j:=r;
      m:=a[k].num;
      repeat
        while a[i].num<m do i:=i+1;
        while a[j].num>m do j:=j-1;
        if i<=j then
          begin
            a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];//说句题外话:这种数组内的交换方法不错
            i:=i+1;j:=j-1;
          end;
      until i>j;
      if i<r then qsort(i,r);
      if l<j then qsort(l,j);
    end;
function find(x,y:real):real;//求出井到各个房屋的距离和
  var sum:real;k,maxx,minn:longint;
    begin
      sum:=0;
      for k:=1 to n do
         begin
           if zx[k]=yx[k] then
             begin
               if zy[k]>yy[k] then
                  begin maxx:=zy[k];minn:=yy[k]; end
                else begin maxx:=yy[k];minn:=zy[k]; end;
               if (y>=minn) and(y<=maxx) then sum:=sum+abs(x-zx[k])
                else sum:=sum+min(sqrt(sqr(x-zx[k])+sqr(y-zy[k])),sqrt(sqr(x-yx[k])+sqr(y-yy[k])));
            end
           else
             if zy[k]=yy[k] then
               begin
                 if zx[k]>yx[k] then
                   begin maxx:=zx[k];minn:=yx[k]; end
                  else begin maxx:=yx[k];minn:=zx[k]; end;
                 if (x>=minn) and(x<=maxx) then sum:=sum+abs(zy[k]-y)
                  else sum:=sum+min(sqrt(sqr(x-zx[k])+sqr(y-zy[k])),sqrt(sqr(x-yx[k])+sqr(y-yy[k])));
               end;
          end;
      find:=sum;
    end;
begin
 assign(input,'village.in');reset(input);
 assign(output,'village.out');rewrite(output);
  readln(n);
  for i:=1 to n do
    begin
      readln(zx[i],zy[i],yx[i],yy[i]);
      c:=max(c,max(zx[i],yx[i]));//c为最大的横坐标
      d:=max(d,max(zy[i],yy[i]));//d为最大的纵坐标
    end;
   m:=0;
  for i:=0 to c do
    for j:=0 to d do
      begin
        sum:=find(i,j);
        m:=m+1;
        a[m].num:=sum;
        a[m].i:=i;a[m].j:=j;
      end;//找坐标为整点的解
  qsort(1,m);//按解从小到大的顺序排列
  ans:=a[1].num;
  for i:=1 to 6 do
    begin
      for lx:=-10 to 10 do
        for ly:=-10 to 10 do
          begin
            summ:=find(a[i].i+lx/10,a[i].j+ly/10);//查找整点附近的实点
            if summ<ans then ans:=summ;
          end;
    end;
  writeln(ans:0:2);
 close(input);close(output);
end.


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值