題目大意:
有一個n個點的凸多邊形,任意兩個點之間有一條筆直的路徑,可以在路徑相交的時候換路。
現在有m條路不能走了,問從點1走到點n的最短路是多少。
題目分析:
這道題其實是讓求一個剩餘路的半平面交的周長(這到底是怎麼想到的orz)。
但是路有n^2條,但是對於一個點,最前面的一條邊可以把後面的所有邊都彈掉,所以後面那些邊都沒有用了,只加最前面的一條邊就可以了,於是就變成邊數就變成了n。
把n到1這條加進來,在統計答案的時候再把這條邊減去即可。
代碼如下:
#include <cstdio>
#include <cmath>
#include <algorithm>
#define N 1200000
using namespace std;
const double eps=1e-7;
inline double sqr(double x) { return x*x; }
int n,m,top;
pair<int,int> l[N];
int tmp[N];
struct point{
double x,y;
point(){}
point(double x,double y):x(x),y(y){}
point operator + (const point &c) const { return point(x+c.x,y+c.y); }
point operator - (const point &c) const { return point(x-c.x,y-c.y); }
double operator * (const point &c) const { return x*c.y-y*c.x; }
double operator | (const point &c) const { return sqrt(sqr(x-c.x)+sqr(y-c.y)); }
point operator * (const double &c) const { return point(x*c,y*c); }
}b[N],h[N];
struct line{
point p,v;
double alpha;
line(){}
line(point a,point b):p(a),v(b-a) { alpha=atan2(v.y,v.x); }
bool operator < (const line &c) const { return alpha<c.alpha; }
point operator ^ (const line &c) const
{
point tmp=p-c.p;
double rate=(c.v*tmp)/(v*c.v);
return p+v*rate;
}
}a[N],p[N];
bool onleft(point c,line l)
{
point tmp=c-l.p;
return l.v*tmp>=0;
}
double half_plane_intersection()
{
sort(a+1,a+1+top);
int l=1,r=1;
for(int i=1;i<=top;i++)
{
while(r-l>=2 && !onleft(p[r-1]^p[r-2],a[i])) r--;
if(r-l>=1 && fabs(p[r-1].v*a[i].v)<=0)
p[r-1]=onleft(a[i].p,p[r-1])?a[i]:p[r-1];
else p[r++]=a[i];
}
for(;;)
{
if(r-l>=2 && !onleft(p[r-1]^p[r-2],p[l])) r--;
else if(r-l>=2 && !onleft(p[l]^p[l+1],p[r-1])) l++;
else break;
}
p[r]=p[l];
for(int i=l;i<r;i++)
h[i]=p[i]^p[i+1];
h[r]=h[l];
double ans=0;
for(int i=l;i<r;i++)
ans+=h[i]|h[i+1];
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lf%lf",&b[i].x,&b[i].y);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&l[i].first,&l[i].second);
if(l[i].first>l[i].second) swap(l[i].first,l[i].second);
}
sort(l+1,l+1+m);
for(int i=1;i<=n;i++) tmp[i]=1;
for(int i=1;i<=m;i++)
if(tmp[l[i].second]==l[i].first) tmp[l[i].second]++;
if(tmp[n]==1)
{
printf("%lf",b[1]|b[n]);
return 0;
}
for(int i=1;i<=n;i++)
if(tmp[i]<i) a[++top]=line(b[i],b[tmp[i]]);
a[++top]=line(b[1],b[n]);
printf("%lf\n",half_plane_intersection()-(b[1]|b[n]));
return 0;
}