题目大意:
给n条线段,用这些线段中的一些围成一个围绕原点的多边形,满足原点发出任意射线与此多边形只有一个交点。求满足条件的多边形的最大周长。(n≤50)
解题思路:
注意所求不一定是凸包。
将所有线段的端点和交点求出,去重后极角排序,每个点向与其处于同一线段且逆时针方向的点连边,再用类似floyed的dp求出最大简单环。
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const double INF=1e9,eps=1e-9;
const int N=1550;
struct point
{
double x,y;
point(){}
point(double _x,double _y):x(_x),y(_y){}
inline friend bool operator == (const point &a,const point &b)
{return a.x==b.x&&a.y==b.y;}
inline friend point operator + (const point &a,const point &b)
{return point(a.x+b.x,a.y+b.y);}
inline friend point operator - (const point &a,const point &b)
{return point(a.x-b.x,a.y-b.y);}
inline friend point operator * (const point &a,const double &b)
{return point(a.x*b,a.y*b);}
inline friend double operator * (const point &a,const point &b)
{return a.x*b.y-a.y*b.x;}
inline double dis(){return sqrt(x*x+y*y);}
inline friend bool operator < (point a,point b)
{
double t1=atan2(a.y,a.x),t2=atan2(b.y,b.x);
if(fabs(t1-t2)<eps)return a.dis()<b.dis();
return t1<t2;
}
};vector<point>p;
struct line{point st,ed;}l[55];
int n,tot;
vector<int>L[55];
double f[N][N],g[N][N],ans;
inline point get_inter(const line &a,const line &b)
{
double s1=(a.st-b.st)*(b.ed-b.st);
double s2=(b.ed-b.st)*(a.ed-b.st);
return a.st+(a.ed-a.st)*(s1/(s1+s2));
}
inline bool online(const point &a,const line &b)
{
point t1=b.st-a,t2=b.ed-a;
return t1.x*t2.x+t1.y*t2.y<=0;
}
int main(){
//freopen("lx.in","r",stdin);
//freopen("lx1.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
point a,b;
scanf("%lf%lf%lf%lf",&l[i].st.x,&l[i].st.y,&l[i].ed.x,&l[i].ed.y);
p.pb(l[i].st),p.pb(l[i].ed);
for(int j=1;j<i;j++)
if((l[i].ed-l[i].st)*(l[j].ed-l[j].st))
{
point q=get_inter(l[i],l[j]);
if(!online(q,l[i])||!online(q,l[j]))continue;
p.pb(q);
}
}
sort(p.begin(),p.end());p.erase(unique(p.begin(),p.end()),p.end());tot=p.size();
for(int i=1;i<=n;i++)
for(int j=0;j<tot;j++)
{
if(fabs((l[i].st-p[j])*(l[i].ed-p[j]))>eps)continue;
if(online(p[j],l[i]))L[i].push_back(j+1);
}
for(int i=1;i<=tot;i++)
for(int j=1;j<=tot;j++)
f[i][j]=g[i][j]=-INF;
for(int i=1;i<=n;i++)
{
int sz=L[i].size();
for(int j=0;j<sz;j++){
for(int k=0;k<sz;k++){
if(j==k)continue;
int t1=L[i][j],t2=L[i][k];
if(p[t1-1]*p[t2-1]<eps)continue;
g[t1][t2]=(p[t1-1]-p[t2-1]).dis();
}
}
}
for(int i=tot;i;i--)
{
f[i][i]=0;
for(int j=tot;j;j--)if(g[i][j]!=-INF)
for(int k=tot;k;k--)if(f[j][k]!=-INF)
f[i][k]=max(f[i][k],g[i][j]+f[j][k]);
for(int j=1;j<=tot;j++)if(g[j][i]!=-INF)
ans=max(ans,f[i][j]+g[j][i]);
}
ans?printf("%.5f\n",ans):puts("0");
}