1 type 2 ans=record 3 p,q:longint; 4 end; 5 var 6 s,u,v,x,y:array[0..10000] of longint; 7 f:array[0..200] of longint; 8 i,j,k,n:longint; 9 anss,ans1,ans2:ans; 10 o1,o2:int64; 11 procedure swap(var x,y:longint); 12 var 13 w:longint; 14 begin 15 w:=x; x:=y; y:=w; 16 end; 17 procedure sort(l,r:longint); 18 var 19 w,mid,i,j:longint; 20 begin 21 i:=l; j:=r; 22 mid:=s[(l+r) div 2]; 23 repeat 24 while s[i]<mid do 25 inc(i); 26 while s[j]>mid do 27 dec(j); 28 if not(i>j) then 29 begin 30 swap(s[i],s[j]); 31 swap(u[i],u[j]); 32 swap(v[i],v[j]); 33 swap(x[i],x[j]); 34 swap(y[i],y[j]); 35 inc(i); 36 dec(j); 37 end; 38 until i>j; 39 if l<j then sort(l,j); 40 if i<r then sort(i,r); 41 end; 42 function find(x:longint):longint; 43 begin 44 if f[x]=x then exit(x); 45 find:=find(f[x]); 46 f[x]:=find; 47 end; 48 function kl:ans; 49 var 50 t,fx,fy,i:longint; 51 sum:ans; 52 begin 53 sort(1,k); 54 for i:=1 to n do f[i]:=i; 55 sum.p:=0; sum.q:=0; t:=0; 56 for i:=1 to k do 57 begin 58 fx:=find(x[i]); 59 fy:=find(y[i]); 60 if fx<>fy then 61 begin 62 f[fx]:=fy; 63 inc(t); 64 sum.p:=sum.p+u[i]; 65 sum.q:=sum.q+v[i]; 66 if t=n-1 then 67 break; 68 end; 69 end; 70 o1:=anss.p*anss.q; 71 o2:=sum.p*sum.q; 72 if (o1>o2)or((o1=o2)and(anss.p>sum.p)) then 73 anss:=sum; 74 kl:=sum; 75 end; 76 procedure solve(a,b:ans); 77 var 78 aa,bb,cc,i:longint; 79 c:ans; 80 begin 81 aa:=(a.q-b.q); bb:=(b.p-a.p); cc:=a.p*b.q-a.q*b.p; 82 for i:=1 to k do 83 s[i]:=u[i]*aa+v[i]*bb; 84 c:=kl; 85 if c.p*aa+c.q*bb+cc>=0 then exit; 86 solve(a,c); 87 solve(c,b); 88 end; 89 begin 90 read(n,k); 91 for i:=1 to k do 92 begin 93 read(x[i],y[i],u[i],v[i]); 94 inc(x[i]); inc(y[i]); 95 end; 96 anss.p:=trunc(sqrt(maxlongint)); anss.q:=trunc(sqrt(maxlongint)); 97 s:=u; ans1:=kl; 98 s:=v; ans2:=kl; 99 solve(ans1,ans2); 100 writeln(anss.p,' ',anss.q); 101 end. 102
(bzoj 2395)
一般的,这种题型会给你两个参数a[i],b[i],先分别根据以a[i]与b[i]做最小生成树,得到最靠近X轴与Y轴的点。
因为题目要求∑a[i]*∑b[j]最小,也就是反比例函数y=k/x中的k最小,我们每次可以选择离直线最远的点。
但是我刚学向量不久,还不会叉积,于是只能用点到直线距离的公式。。。
每次求出两个边界点直线的解析式 ax+by+c=0;
由(x1,y1),(x2,y2) ;
可算出a=(y1-y2); b=(x2-x1); c=x1*y2-x2*y1;
直线到点(x,y)的距离为:a*x+b*y+c/√(a^2+b^2)
所以可以算出每个点到直线的距离大小又因为与点有关的是x,y,所以只要比较(a*x+b*y)的大小再进行排序
就求出了可能更优的边,再一直递归去求可能更优的点。
但递归边界是什么呢?
当求出的最优点在直线外侧时
很显然,当a*x+b*y+c>=0时
这一定没有A.B优,这时就可以退出了