首页 > 其他 > 详细

BZOJ2191Splite

时间:2017-01-08 18:51:25      阅读:142      评论:0      收藏:0      [点我收藏+]

Description

给两个多边形,问否在平移旋转不翻转不重叠的情况下拼成一个凸多边形。

Input

每组第一行一个数N表示第一个多边形的顶点数,下接N行按顺序(逆/顺时针)给出顶点坐标,再下一行给一个数M表示第二个多边形的顶点数,下接M行按顺序给出顶点坐标。

Output

对于每组数据,输出一行0/1,1表示能,0表示不能。

Sample Input

4
0 0 0 1 1 1 1 0 4 0 0 0 1 1 1 1 0 4 0 0 0 1 1 1 1 0 4 0 0 0 1 1 1 1 0

Sample Output

1
1

HINT

对于100%的数据,N<=1000,M<=1000,顶点坐标为实数,标程精度1e-8

 

题解:

平面计算几何题。每次枚举相拼的两条边,在按顺序扫过两个多边形对应的变,检查是否是无缝屏接,拼好后是否是凸多边形。

注意给点的顺序不一定都是逆时针的,先按照给点的顺序扫过每一条边,记录下角度的偏转情况。若最终偏转为-2π,则为顺时针;若为2π,则为逆时针。

通过倒着排序给出的点,使两个多边形都变成是逆时针的,就可以正常做了。

 

代码:

技术分享
var
  i,j,k,l,n,m:longint;
  a,b:array[-1000..2000,1..2]of extended;
  tt:array[1..2]of extended;
  e:extended;
function dis(x,y,xx,yy:extended):extended;
begin
  exit(sqrt(sqr(x-xx)+sqr(y-yy)));
end;
function xj2(x,y:extended):extended;
var i,j,k,l:longint;
begin
  if(abs(x)<0.0000001)and(y>0)then exit(pi/2);
  if(abs(x)<0.0000001)and(y<0)then exit(3*pi/2);
  if(abs(y)<0.0000001)and(x>0)then exit(0);
  if(abs(y)<0.0000001)and(x<0)then exit(pi);
  if(x>0)and(y>0)then exit(arctan(y/x));
  if(x>0)and(y<0)then exit(2*pi-arctan(-y/x));
  if(x<0)and(y>0)then exit(pi/2+arctan(-x/y));
  if(x<0)and(y<0)then exit(pi+arctan(y/x));
end;
function xj(x,y,xx,yy,xxx,yyy:extended):extended;
var z1,z2:extended;
begin
  z1:=xj2(x-xx,y-yy);
  z2:=xj2(xxx-xx,yyy-yy);
  while z2>0.0000001+z1 do z2:=z2-2*pi;
  exit(z1-z2);
end;
function ss:longint;
var i,j,ii,jj,k,l:longint;
  z1,z2,z3:extended;
begin
  for i:=1 to n do
  for j:=1 to m do
  if abs(dis(a[i-1,1],a[i-1,2],a[i,1],a[i,2])
  -dis(b[j+1,1],b[j+1,2],b[j,1],b[j,2]))<0.0000001 then
  begin
    z1:=xj(a[i-2,1],a[i-2,2],a[i-1,1],a[i-1,2],a[i,1],a[i,2]);
    z2:=xj(b[j+2,1],b[j+2,2],b[j+1,1],b[j+1,2],b[j,1],b[j,2]);
    while z2>0.0000001+z1 do z2:=z2-2*pi;
    if z1-z2>pi+0.0000001 then continue;
    ii:=i+1; jj:=j-1; l:=0;
    while true do
    begin
      z1:=xj(a[ii-2,1],a[ii-2,2],a[ii-1,1],a[ii-1,2],a[ii,1],a[ii,2]);
      z2:=xj(b[jj+2,1],b[jj+2,2],b[jj+1,1],b[jj+1,2],b[jj,1],b[jj,2]);
      while z2>0.0000001+z1 do z2:=z2-2*pi;
      if z1-z2<0.0000001 then
      begin
        if abs(dis(a[ii-1,1],a[ii-1,2],a[ii,1],a[ii,2])
        -dis(b[jj+1,1],b[jj+1,2],b[jj,1],b[jj,2]))<0.0000001 then
        begin inc(ii); dec(jj); end else begin l:=1; break; end;
        continue;
      end;
      if z1-z2<pi-0.0000001 then
      begin l:=1; break; end;
      break;
    end;
    if l=0 then
    begin
      for k:=ii to i+n-2 do
      if xj(a[k-1,1],a[k-1,2],a[k,1],a[k,2],a[k+1,1],a[k+1,2])>pi+0.0000001
      then begin l:=1; break; end;
      for k:=jj downto j-m+2 do
      if xj(b[k+1,1],b[k+1,2],b[k,1],b[k,2],b[k-1,1],b[k-1,2])<pi-0.0000001
      then begin l:=1; break; end;
      if l=0 then exit(1);
    end;
  end;
  exit(0);
end;
begin
  while not eof do
  begin
    readln(n);
    for i:=1 to n do readln(a[i,1],a[i,2]);
    a[n+1]:=a[1]; a[0]:=a[n]; e:=0;
    for i:=1 to n do
    e:=e+xj(a[i-1,1],a[i-1,2],a[i,1],a[i,2],a[i+1,1],a[i+1,2])-pi;
    if e>0 then
    begin
      for i:=1 to n div 2 do begin tt:=a[i]; a[i]:=a[n-i+1]; a[n-i+1]:=tt; end;
    end;
    for i:=1 to n do a[i-n]:=a[i];
    for i:=1 to n do a[i+n]:=a[i];
    readln(m);
    for i:=1 to m do readln(b[i,1],b[i,2]);
    b[m+1]:=b[1]; b[0]:=b[m]; e:=0;
    for i:=1 to m do
    e:=e+xj(b[i-1,1],b[i-1,2],b[i,1],b[i,2],b[i+1,1],b[i+1,2])-pi;
    if e>0 then
    begin
      for i:=1 to m div 2 do begin tt:=b[i]; b[i]:=b[m-i+1]; b[m-i+1]:=tt; end;
    end;
    for i:=1 to m do b[i-m]:=b[i];
    for i:=1 to m do b[i+m]:=b[i];
    writeln(ss);
  end;
end.
View Code

BZOJ2191Splite

原文:http://www.cnblogs.com/GhostReach/p/6262459.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!