bzoj 1696 [Usaco2007 Feb]Buildin…

Description

经过多年的积蓄,农夫JOHN决定造一个新的牛舍。他知道所有N(2 <= N <= 10,000)头牛的吃草位置,所以他想把牛舍造在最方便的地方。每一头牛吃草的位置是一个整数点(X_i, Y_i) (-10,000 <= X_i <= 10,000; -10,000 <= Y_i <= 10,000)。 没有两头牛的吃草位置是相邻的。 JOHN决定把牛舍造在一个没有牛吃草的整数点上。如果牛舍在(X, Y),在(X_i, Y_i)的牛到牛舍的距离是|X-X_i|+|Y-Y_i|。 JOHN把牛舍造在哪儿才能使所有牛到牛舍的距离和最低?

Input

第1行: 一个数,N。第2~N+1行:第i+1行 包含第i头牛的位置(X_i, Y_i)。

Output

第1行: 两个数,最小距离和和所有可能达到这个距离和的牛舍位置的数目。

Sample Input

4
1 -3
0 1
-2 1
1 -1

输入解释:

一共有4头牛,位置分别为(1, -3), (0, 1), (-2, 1), 和(1, -1).

Sample Output

10 4

输出解释:
最小距离和是10,可以在牛舍位于 (0, -1), (0, 0), (1, 0), (1, 1)时达到。
 
题目大意:在二维平面内找一个不与一直点重合的点使得给出点到该点的距离最短。
距离d=abs(x[i]-x)+abs(y[i]-y)  (1<=i<=n)
对于所有点的距离,可以理解成x方向的距离和y方向的距离,而且这两个距离是相互独立的。可以看成求两个方向的最大化问题。
这样就可以很容易看出来,对于确定最小点o的x坐标,如果是偶数个点,就找出最接近中位数的两个坐标,则o的坐标落在这之间,y坐标同理可求。对于奇数个点,o的x,y坐标唯一确定,但有可能和奶牛重合,那么只要扫一遍周围四个点即可。
 
AC CODE
 
program hy_1696;
var x,y,a: array [ 1..10000 ] of longint ;
     n,x1,x2,y1,y2,x0,y0,tmp,ans,i: longint ;
//============================================================================
procedure qsort(l,r: longint );
var k,i,j,t: longint ;
begin
   k:=a[(l+r) shr 1 ]; i:=l; j:=r;
   repeat
     while a[i]<k do inc(i);
     while a[j]>k do dec(j);
     if i<=j then
     begin
       t:=a[i]; a[i]:=a[j]; a[j]:=t;
       inc(i); dec(j);
     end ;
   until i>j;
   if j>l then qsort(l,j);
   if i<r then qsort(i,r);
end ;
//============================================================================
procedure find(g,h: longint );
var i: longint ;
begin
   tmp:= 0 ;
   for i:= 1 to n do tmp:=tmp+ abs (x[i]-g)+ abs (y[i]-h);
end ;
//============================================================================
procedure walk;
var i,len,ans,area: longint ;
begin
   x0:=x1; y0:=y1; len:= 0 ;
   area:=(x2-x1+ 1 )*(y2-y1+ 1 );
   for i:= 1 to n do
   begin
     len:=len+ abs (x[i]-x0)+ abs (y[i]-y0);
     if (x[i]>=x1) and (x[i]<=x2) and (y[i]>=y1) and (y[i]<=y2) then dec(area);
   end ;
   if area> 0 then writeln (len, ' ' ,area) else
   begin
     ans:=maxlongint; area:= 0 ;
     find(x0,y0- 1 );
     if tmp<ans then
     begin ans:=tmp; area:= 1 ; end else
     if tmp=ans then inc(area);
     find(x0- 1 ,y0);
     if tmp<ans then
     begin ans:=tmp; area:= 1 ; end else
     if tmp=ans then inc(area);
     find(x0,y0+ 1 );
     if tmp<ans then
     begin ans:=tmp; area:= 1 ; end else
     if tmp=ans then inc(area);
     find(x0+ 1 ,y0);
     if tmp<ans then
     begin ans:=tmp; area:= 1 ; end else
     if tmp=ans then inc(area);
     writeln (ans, ' ' ,area);
   end ;
end ;
//============================================================================
begin
   readln(n);
   for i:= 1 to n do readln(x[i],y[i]);
   for i:= 1 to n do a[i]:=x[i]; qsort( 1 ,n);
   if odd(n) then
   begin
     x1:=a[n shr 1 + 1 ];
     x2:=x1;
   end else
   begin
     x1:=a[n shr 1 ];
     x2:=a[n shr 1 + 1 ];
   end ;
   for i:= 1 to n do a[i]:=y[i]; qsort( 1 ,n);
   if odd(n) then
   begin
     y1:=a[n shr 1 + 1 ];
     y2:=y1;
   end else
   begin
     y1:=a[n shr 1 ];
     y2:=a[n shr 1 + 1 ];
   end ;
   walk;
end .
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值