Описание Два многоугольника на плоскости заданы координатами своих вершин Задание Требуется вычислить площадь пересечения этих многоугольников, то есть сумму площадей тех кусков, которые образуются при их пересечении и принадлежат каждому из них. При этом вы можете предполагать, что: Многоугольники выпуклые, а координаты их вершин даны в произвольном порядкеХотя бы один из многоугольников невыпуклый, но известно, что у каждого из многоугольников не более одного угла, большего 180°, а координаты вершин даны в порядке обхода по часовой стрелкеВаша программа по входным данным должна сама определить, какой из этих двух случаев имеет место Входные данные Первая строка входного файла содержит целое число N – количество вершин в первом многоугольнике (3≤N≤50). Во второй строке записаны координаты этих вершин. Третья и четвертая строки таким же образом задают второй многоугольник. Координаты всех вершин являются целыми числами из диапазона [-32768,32767] Выходные данные Выведите в выходной файл искомую площадь не менее чем с шестью верными значащими цифрами Например: CROSSING.IN 3 0 3 0 -3 -3 0 5 -1 1 2 1 1 0 2 -1 -1 -1 CROSSING.OUT 2.0
Идеи Пересечение
отрезков, полярный угол, площадь многоугольника Комментарии Отсортируем вершины каждого из многоугольников по полярному углу относительно его центра масс. Если в результате получились два выпуклых многоугольника (для проверки выпуклости используйте критерий из задачи 4.1), значит нам предстоит решать пункт A, иначе - пункт B Разберем пункт A. Очевидно, что пересечение двух выпуклых многоугольников также является выпуклым многоугольником. Какие точки будут его вершинами? Во-первых, все точки пересечения двух многоугольников. Чтобы их найти, нужно пересечь все стороны одного многоугольника со всеми сторонами другого. Во-вторых, все вершины первого многоугольника, принадлежащие второму, и наоборот, все вершины второго, принадлежащие первому. Определив все вершины пересечения, упорядочим их, отсортировав по полярному углу относительно центра масс. Далее считаем площадь получившегося многоугольника Пункт B сводится к пункту A следующим образом. Прямая, проведенная через любую из сторон угла, большего 180°, разбивает невыпуклый многоугольник на два выпуклых. Пересекая получившиеся выпуклые многоугольники (как в пункте A) и суммируя площади их пересечений, найдем ответ на пункт B Решение {$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,R-,S+,V+,X+} {$M 65520,0,655360} program crossing; uses crt; const eps=0.000000001; type pointtype=record x,y:real; end; linetype=record a,b,c:real; x1,x2,y1,y2:real; end; ntype=record h:array[1..100] of pointtype; n:integer; end; var a:array[1..3] of ntype; d1,d2:linetype; p1,p2,s1,s2:ntype; p:pointtype; i:integer; ss1,ss2,ss3,ss:real; procedure makeabc(var p:linetype); begin with p do begin a:=y1-y2; b:=x2-x1; c:=x1*y2-x2*y1; end; end; function r(r1,r2:real):boolean; begin if (r1>=r2*(1-eps)) and (r1<=r2*(1+eps)) then r:=true else r:=false; end; function twoline(p1,p2:linetype;var s:pointtype):boolean; var d:real; begin d:=p1.a*p2.b-p1.b*p2.a; if r(d,0) then twoline:=false else begin with s do begin x:=-(p1.c*p2.b-p2.c*p1.b)/d; y:=-(p1.a*p2.c-p2.a*p1.c)/d; end; end; end; procedure swap(var i,j:real); var c:real; begin c:=i; i:=j; j:=c; end; procedure sortx(var p:linetype); begin with p do if x1>x2 then swap(x1,x2); end; procedure sorty(var p:linetype); begin with p do if y1>y2 then swap(y1,y2); end; function pointotr(p:linetype;s:pointtype):boolean; var f:boolean; begin makeabc(p); f:=true; with p do begin sortx(p); if not ((x1-abs(x1*eps)<=s.x) and (x2+abs(x2*eps)>=s.x)) then f:=false; sorty(p); if not ((y1-abs(y1*eps)<=s.y) and (y2+abs(y2*eps)>=s.y)) then f:=false; end; pointotr:=f; end; function twootr(p1,p2:linetype;var s:pointtype):boolean; var i,j:integer; begin makeabc(p1); makeabc(p2); if twoline(p1,p2,s)=false then twootr:=false else begin if (pointotr(p1,s) and pointotr(p2,s)) then twootr:=true else twootr:=false; end; end; function updown(p:linetype;s:pointtype):boolean; var i,j:integer; d:real; begin makeabc(p); with p do d:=(a*s.x+b*s.y+c)/sqrt(a*a+b*b); if d<0 then updown:=false else updown:=true; end; function s3(p1,p2,p3:pointtype):real; begin s3:=1/2*((p1.x-p3.x)*(p2.y-p3.y)-(p2.x-p3.x)*(p1.y-p3.y)); end; function sn(p:ntype):real; var i,j:integer; pp:pointtype; s:real; begin pp.x:=0; pp.y:=0; s:=0; for i:=1 to p.n do begin if i<>p.n then s:=s+s3(pp,p.h[i],p.h[i+1]) else s:=s+s3(pp,p.h[i],p.h[1]); end; sn:=s; end; procedure makeline(p1,p2:pointtype;var ll:linetype); begin ll.x1:=p1.x; ll.y1:=p1.y; ll.x2:=p2.x; ll.y2:=p2.y; makeabc(ll); end; function pointandotr(p:linetype;s:pointtype):boolean; var d:real; begin makeabc(p); if pointotr(p,s)=false then begin pointandotr:=false; exit; end; with p do d:=(a*s.x+b*s.y+c)/sqrt(a*a+b*b); if abs(d)then pointandotr:=true else pointandotr:=false; end; function alloneside(p:ntype;i,j,del:integer):boolean; var k,l:integer; ll:linetype; fir,fend,fgood:boolean; begin ll.x1:=p.h[i].x; ll.y1:=p.h[i].y; ll.x2:=p.h[j].x; ll.y2:=p.h[j].y; fend:=true; fir:=true; for k:=1 to p.n do if (k<>del) and (k<>i) and (k<>j) then begin if fir then begin fir:=false; fgood:=updown(ll,p.h[k]); end else if fgood<>updown(ll,p.h[k]) then fend:=false; end; alloneside:=fend; end; procedure delown(var p:ntype); var k,i,j,l,i1,i2:integer; ll:linetype; label begfor; begin begfor: for i:=1 to p.n do for j:=1 to p.n do if i<>j then begin makeline(p.h[i],p.h[j],ll); for k:=1 to p.n do if (k<>i) and (k<>j) and (pointandotr(ll,p.h[k])) and (alloneside(p,i,j,k)) then begin dec(p.n); for l:=k to p.n do p.h[l]:=p.h[l+1]; goto begfor; end; end; end; procedure sortxy(var p:ntype); var s:set of byte; l:ntype; allgood,f,ftek,ans,fend:boolean; ntek,j,i,last:integer; ll:linetype; begin s:=[]; l:=p; s:=[1]; last:=1; ntek:=1; allgood:=true; while allgood do begin allgood:=false; i:=1; while (i<>p.n+1) and (not allgood) do if not (i in s) then begin ans:=true; fend:=true; for j:=1 to p.n do if (j<>i) and (j<>last) then begin ll.x1:=p.h[last].x; ll.y1:=p.h[last].y; ll.x2:=p.h[i].x; ll.y2:=p.h[i].y; ftek:=updown(ll,p.h[j]); if ans then f:=ftek else if f<>ftek then fend:=false; ans:=false; end; allgood:=fend; if fend=false then inc(i); end else inc(i); if allgood then begin last:=i; s:=s+[i]; inc(ntek); l.h[ntek]:=p.h[i]; end; end; p:=l; end; procedure makedel(var p,pp,ss:ntype); var s2,s:set of byte; l:ntype; allgood,f,ftek,ans,fend:boolean; ntek,j,i,last:integer; ll:linetype; begin s:=[]; for i:=1 to p.n do if not (i in s) then for j:=1 to p.n do if (i<>j) and (alloneside(p,i,j,0)) then s:=s+[i]+[j]; pp.n:=0; ss.n:=0; for i:=1 to p.n do if i in s then begin inc(pp.n); pp.h[pp.n]:=p.h[i]; end; s2:=[]; for i:=1 to p.n do if not (i in s) then begin s2:=s2+[i]; if i=1 then s2:=s2+[p.n] else s2:=s2+[i-1]; if i=p.n then s2:=s2+[1] else s2:=s2+[i+1]; end; ss.n:=0; for i:=1 to p.n do if i in s2 then begin inc(ss.n); ss.h[ss.n]:=p.h[i]; end; sortxy(pp); sortxy(ss); end; procedure readfile; var i,j:integer; f:text; begin assign(f,'crossing.in'); reset(f); readln(f,a[1].n); for i:=1 to a[1].n do begin with a[1].h[i] do read(f,x,y); end; readln(f); readln(f,a[2].n); for i:=1 to a[2].n do begin with a[2].h[i] do read(f,x,y); end; close(f); end; function pointn(p:ntype;s:pointtype):boolean; var i,j:integer; f:boolean; ll:linetype; begin if p.n<3 then begin pointn:=false; exit; end; f:=true; for i:=1 to p.n-2 do begin makeline(p.h[i],p.h[i+1],ll); if updown(ll,s)<>updown(ll,p.h[i+2]) then begin pointn:=false; exit; end; end; makeline(p.h[p.n-1],p.h[p.n],ll); if updown(ll,s)<>updown(ll,p.h[1]) then begin pointn:=false; exit; end; makeline(p.h[p.n],p.h[1],ll); if updown(ll,s)<>updown(ll,p.h[2]) then begin pointn:=false; exit; end; pointn:=true; end; function makes(p1,p2:ntype):real; var i,j,k:integer; s:pointtype; l1,l2:linetype; s3,p3:ntype; sss:real; label begfor; begin a[3].n:=0; for i:=1 to p1.n do if pointn(p2,p1.h[i]) then begin inc(a[3].n); a[3].h[a[3].n]:=p1.h[i]; end; for i:=1 to p2.n do if pointn(p1,p2.h[i]) then begin inc(a[3].n); a[3].h[a[3].n]:=p2.h[i]; end; for i:=1 to p1.n do begin if i=p1.n then makeline(p1.h[i],p1.h[1],l1) else makeline(p1.h[i],p1.h[i+1],l1); for j:=1 to p2.n do begin if j=p2.n then makeline(p2.h[j],p2.h[1],l2) else makeline(p2.h[j],p2.h[j+1],l2); if twootr(l1,l2,s) then begin inc(a[3].n); a[3].h[a[3].n]:=s; end; end; end; begfor: for i:=1 to a[3].n do for j:=1 to a[3].n do if ((a[3].h[i].x=a[3].h[j].x) and (a[3].h[i].y=a[3].h[j].y)) and (i<>j) then begin dec(a[3].n); for k:=j to a[3].n do a[3].h[k]:=a[3].h[k+1]; goto begfor; end; makedel(a[3],p3,s3); sss:=abs(sn(p3)); makes:=sss; end; procedure writefile; var f:text; begin assign(f,'crossing.out'); rewrite(f); writeln(f,ss:10:10); close(f); end; begin readfile; delown(a[1]); delown(a[2]); makedel(a[1],p1,s1); makedel(a[2],p2,s2); ss1:=makes(p1,p2); ss2:=makes(s1,p2); ss3:=makes(s2,p1); ss:=makes(s1,s2); ss:=ss1-ss2-ss3+ss; writefile; end.
|