如果发现广告等破坏行为,请尽量将条目恢复到较早的版本而不是把相应内容直接删除,谢谢合作。

URAL/1065

来自"NOCOW"

跳转到: 导航, 搜索

先连边,i点到j点有边的时候,当前仅当i到j这一块中不包含任何纪念碑,可以以i为一端点,以j,j-1为另外两个点的三角形来判断其中是否包含纪念碑;

然后就是求最小环了;

特别注意两点:

(1)当前三角形如果为一条直线则跳过

(2)最后的路线不能为一条直线

program djy;
var
  x,y:array[1..100] of int64;
  xx,yy:array[1..1000] of int64;
  flag:array[1..100,1..100] of boolean;
  dis:array[1..100,1..100] of extended;
  n,m:longint;
procedure init;
var
  i:longint;
begin
  readln(n,m);
  for i:=1 to n do
  begin
    readln(x[i],y[i]);
    x[n+i]:=x[i];
    y[n+i]:=y[i];
  end;
  for i:=1 to m do
  readln(xx[i],yy[i]);
end;
function chaji(x1,y1,x2,y2:int64):int64;
begin
  chaji:=x1*y2-x2*y1;
end;
function cross(x1,y1,x2,y2,x3,y3,x4,y4:int64):boolean;     {判断线段相交}
begin
  if chaji(x2-x1,y2-y1,x3-x1,y3-y1)*chaji(x2-x1,y2-y1,x4-x1,y4-y1)<0 then
  if chaji(x4-x3,y4-y3,x1-x3,y1-y3)*chaji(x4-x3,y4-y3,x2-x3,y2-y3)<0 then exit(true);
  exit(false);
end;
function inside(x1,y1,x2,y2,x3,y3,p,q:int64):boolean;    {判断(p,q)是否在三角形内,用(p,q)分别向三顶点连一条直线,看是否与剩下两点构成的直线相交}
begin
  if cross(x1,y1,p,q,x2,y2,x3,y3)=true then exit(false);
  if cross(x2,y2,p,q,x3,y3,x1,y1)=true then exit(false);
  if cross(x3,y3,p,q,x1,y1,x2,y2)=true then exit(false);
  exit(true);
end;
procedure prepare;
var
  i,j,k:longint;
  check:boolean;
begin
  for i:=1 to n do
  begin
    flag[i,i+1]:=true;
    for j:=i+2 to i+n-1 do
    begin
      check:=true;
      if chaji(x[i]-x[j-1],y[i]-y[j-1],x[i]-x[j],y[i]-y[j])<>0 then   {检查三角形是否为一直线}
      begin
        for k:=1 to m do
        if inside(x[i],y[i],x[j-1],y[j-1],x[j],y[j],xx[k],yy[k])=true then check:=false;
      end;
      if check=true then flag[i,j]:=true
      else break;
    end;
  end;
end;
procedure main;
var
  i,j,k:longint;
begin
  for i:=1 to n do
  for j:=i+1 to i+n-1 do
  if flag[i,j]=true then dis[i,j]:=sqrt(sqr(x[i]-x[j])+sqr(y[i]-y[j]))
  else dis[i,j]:=100000000;
  for k:=1 to n do
  for i:=1 to k-1 do
  for j:=k+1 to n do
  if dis[i,k]+dis[k,j]<dis[i,j] then dis[i,j]:=dis[i,k]+dis[k,j];
end;
procedure print;
var
  i,j,k:longint;
  ans:extended;
begin
  ans:=100000000;
  for i:=1 to n do
  for j:=i+1 to n do
  for k:=j+1 to n do                         {检查路线是否为一条直线}
  if (dis[i,j]+dis[j,k]+dis[k,i+n]<ans) and (chaji(x[i]-x[j],y[i]-y[j],x[i]-x[k],y[i]-y[k])<>0) then ans:=dis[i,j]+dis[j,k]+dis[k,i+n];
  writeln(ans:0:2);
end;
begin
  init;
  prepare;
  main;
  print;
end.
个人工具