题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=209
题意:给出一些直线。这些直线将平面分成好多块。求这些块中各个封闭图形的面积。
思路:求出所有交点。任意两个交点之间有直接的边相连则这两个点连一条边(两条双向边),并为每个边编号。搜封闭图形时每次找最左侧的。
int DB(double x)
{
if(x>1e-10) return 1;
if(x<-1e-10) return -1;
return 0;
}
class point
{
public:
double x,y;
point(){}
point(double _x,double _y)
{
x=_x;
y=_y;
}
void get()
{
RD(x,y);
}
point operator+(point a)
{
return point(x+a.x,y+a.y);
}
point operator-(point a)
{
return point(x-a.x,y-a.y);
}
double operator*(point a)
{
return x*a.y-y*a.x;
}
point operator*(double t)
{
return point(x*t,y*t);
}
double operator^(point a)
{
return x*a.x+y*a.y;
}
double getLen()
{
return sqrt(x*x+y*y);
}
point operator/(double t)
{
return point(x/t,y/t);
}
double getAng(point a)
{
return atan2(*this*a,*this^a);
}
int operator==(const point &a) const
{
return DB(x-a.x)==0&&DB(y-a.y)==0;
}
int operator<(const point &a) const
{
if(DB(x-a.x)) return x<a.x;
return y<a.y;
}
void print()
{
printf("%.6lf %.6lf\n",x,y);
}
};
const int N=85;
point L[N][2];
vector<point> p,G[N];
vector<pair<int,int> > g[N*N*N];
int visit[N*N*N];
int n;
int isParal(point a,point b,point p,point q)
{
double x=(b.x-a.x)*(q.y-p.y);
double y=(b.y-a.y)*(q.x-p.x);
return !DB(x-y);
}
point getCross(point a,point b,point p,point q)
{
double s1=(a-p)*(b-p);
double s2=(b-q)*(a-q);
return (p*s2+q*s1)/(s1+s2);
}
int cmp(point a,point b)
{
if(DB(a.x-b.x)) return a.x<b.x;
return a.y<b.y;
}
int m;
map<point,int> Map;
point x,y;
double cross(point a,point b,point p)
{
return (b-a)*(p-a);
}
int cmp1(pair<int,int> A,pair<int,int> B)
{
point a=p[A.first];
point b=p[B.first];
double xx=cross(x,y,a);
double yy=cross(x,y,b);
if(DB(xx)!=DB(yy)) return DB(xx)>DB(yy);
xx=(a-y).getAng(x-y);
yy=(b-y).getAng(x-y);
return DB(xx-yy)<0;
}
void build()
{
int i,j,k,t,x=0;
FOR1(i,n)
{
for(j=0;j+1<SZ(G[i]);j++)
{
k=Map[G[i][j]];
t=Map[G[i][j+1]];
if(k==t) continue;
g[k].pb(MP(t,++x));
g[t].pb(MP(k,++x));
}
}
}
vector<double> s;
void calArea(vector<int> a)
{
double ans=0;
int i;
point x,y;
a.pb(a[0]);
for(i=0;i+1<SZ(a);i++)
{
x=p[a[i]];
y=p[a[i+1]];
ans+=x*y;
}
ans=fabs(ans)/2;
s.pb(ans);
}
void DFS(int cur,int pre,vector<int> temp,int t)
{
if(cur==t)
{
calArea(temp);
return;
}
temp.pb(cur);
int i,j,k;
x=p[pre];
y=p[cur];
sort(g[cur].begin(),g[cur].end(),cmp1);
for(i=0;i<SZ(g[cur]);i++)
{
j=g[cur][i].first;
k=g[cur][i].second;
if(j==pre||visit[k]) continue;
if(DB(cross(p[pre],p[cur],p[j]))<=0) return;
visit[k]=1;
DFS(j,cur,temp,t);
return;
}
}
void cal()
{
vector<int> temp;
int i,j,k,t;
for(i=0;i<m;i++)
{
for(j=0;j<SZ(g[i]);j++)
{
k=g[i][j].first;
t=g[i][j].second;
if(visit[t]||j&&g[i][j-1].first==k) continue;
visit[t]=1;
temp.clear();
temp.pb(i);
DFS(k,i,temp,i);
}
}
sort(s.begin(),s.end());
PR(SZ(s));
FOR0(i,SZ(s)) printf("%.8lf\n",s[i]);
}
int main()
{
RD(n);
int i,j,k;
point temp;
FOR1(i,n)
{
L[i][0].get();
L[i][1].get();
for(j=1;j<i;j++)
{
if(isParal(L[j][0],L[j][1],L[i][0],L[i][1])) continue;
temp=getCross(L[j][0],L[j][1],L[i][0],L[i][1]);
for(k=0;k<SZ(G[i]);k++) if(G[i][k]==temp) break;
if(k>=SZ(G[i])) G[i].pb(temp);
for(k=0;k<SZ(G[j]);k++) if(G[j][k]==temp) break;
if(k>=SZ(G[j])) G[j].pb(temp);
p.pb(temp);
}
}
sort(p.begin(),p.end(),cmp);
m=unique(p.begin(),p.end())-p.begin();
FOR0(i,m) Map[p[i]]=i;
FOR1(i,n) sort(G[i].begin(),G[i].end(),cmp);
build();
cal();
}