[POJ2954&POJ1265]皮克定理的应用两例
皮克定理:
在一个多边形中。用I表示多边形内部的点数,E来表示多边形边上的点数,S表示多边形的面积。
满足:S:=I+E/2-1;
解决这一类题可能运用到的:
求E,一条边(x1,y1,x2,y2)上的点数(包括两个顶点)=gcd(abs(x1-x2),abs(y1-y2))+1;
求S:刚开始做POJ2954的时候莫名其妙一直WA,用了海伦公式求面积,后来又改用割补法,还是WA。发现面积还是用叉积算的好。
在八十中走廊里看过的书都忘光了啊...这么典型的叉积运用都会选择小学方法...不过至今没弄明白为什么海伦公式和割补法的误差那么大...
POJ2954
1 program poj2954; 2 var x1,y1,x2,y2,x3,y3,e:longint; 3 s:extended; 4 5 function gcd(x,y:longint):longint; 6 begin 7 if y=0 then exit(x) else 8 exit(gcd(y,x mod y)); 9 end; 10 11 function calc_area(x1,y1,x2,y2,x3,y3:longint):extended; 12 begin 13 exit(abs((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1))/2); 14 end; 15 16 function solve(x1,y1,x2,y2:longint):longint; 17 begin 18 exit(gcd(abs(x1-x2),abs(y1-y2))+1); 19 end; 20 21 begin 22 //assign(input,'poj2954.in');reset(input); 23 //assign(output,'a.out');rewrite(output); 24 while not eof do 25 begin 26 readln(x1,y1,x2,y2,x3,y3); 27 if (x1=0)and(y1=0)and(x2=0)and(y2=0)and(x3=0)and(y3=0) then halt; 28 s:=calc_area(x1,y1,x2,y2,x3,y3); 29 e:=solve(x1,y1,x2,y2)+solve(x1,y1,x3,y3)+solve(x2,y2,x3,y3)-3; 30 writeln(trunc(s-e/2+1)); 31 end; 32 end.
POJ1265
1 program poj1265; 2 const maxn=110; 3 type point=record x,y:longint;end; 4 var t,test,n,e,i,tx,ty:longint; 5 s:extended; 6 a:array[-1..maxn]of point; 7 8 function gcd(x,y:longint):longint; 9 begin 10 if y=0 then exit(x) else 11 exit(gcd(y,x mod y)); 12 end; 13 14 function cross(p0,p1,p2:point):double; 15 begin 16 exit((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y)); 17 end; 18 19 begin 20 //assign(input,'poj1265.in');reset(input); 21 readln(test); 22 for t:=1 to test do 23 begin 24 readln(n); 25 a[0].x:=0;a[0].y:=0; 26 for i:=1 to n do 27 begin 28 readln(tx,ty); 29 a[i].x:=a[i-1].x+tx; 30 a[i].y:=a[i-1].y+ty; 31 end; 32 e:=0; 33 for i:=0 to n-1 do inc(e,gcd(abs(a[i].x-a[i+1].x),abs(a[i].y-a[i+1].y))); 34 s:=0; 35 for i:=2 to n do s:=s+cross(a[0],a[i-1],a[i])/2; 36 s:=abs(s); 37 writeln('Scenario #',t,':'); 38 writeln(trunc(s+1-e/2),' ',e,' ',s:0:1); 39 writeln; 40 end; 41 end.