SGU209 Areas 【平面图】
来源:互联网 发布:淘宝达人推广有用吗 编辑:程序博客网 时间:2024/05/01 18:05
题目大意:
给出n条直线,问直线围成的所有闭合区域的个数及面积,按面积大小升序输出。(n<=80)
解题思路:
①我们需要求出两两直线的交点;
②再对每条直线上的交点排序,来求出所有分割成的线段并连边(正反两条边);
③对于连向一个点的几条线段,对它们进行极角排序进行处理,这样就可以对于每条边记录走过去后下一条该走那条边了,我们脑补一下应该可以知道是它排序后相邻边的反向边。
④找循环,利用叉积求面积。
代码中用vector方便去重点,重边。
#include<bits/stdc++.h>#define ll long longusing namespace std;const int N=105,M=20005;const double eps=1e-8;struct point{ double x,y; point(){} point(double _x,double _y):x(_x),y(_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.x+a.y*b.y;} inline friend double operator ^ (const point &a,const point &b) {return a.x*b.y-a.y*b.x;} inline friend bool operator < (const point &a,const point &b) {return a.x-b.x<-eps||(abs(a.x-b.x)<eps&&a.y-b.y<-eps);} inline friend bool operator == (const point &a,const point &b) {return abs(a.x-b.x)<eps&&abs(a.y-b.y)<eps;} inline double len(){return sqrt(x*x+y*y);} inline point unit(){double d=len();return point(x/d,y/d);} inline double ang(){return atan2(y,x);}};struct line{ point st,ed,v;}l[N];vector<point>p;vector<double>ans;int n,tot=-1,first[M],to[M],nxt[M],nxte[M];bool vis[M];point get_inter(line a,line b){ double s1=b.v^(a.st-b.st); double s2=((a.ed-b.st)^b.v)+s1; return a.st+a.v*(s1/s2);}int get_id(const point &a){ return lower_bound(p.begin(),p.end(),a)-p.begin();}void add(int x,int y){ nxt[++tot]=first[x],first[x]=tot,to[tot]=y;}void Init(){ memset(first,-1,sizeof(first)); memset(nxte,-1,sizeof(nxte)); scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%lf%lf%lf%lf",&l[i].st.x,&l[i].st.y,&l[i].ed.x,&l[i].ed.y); l[i].v=(l[i].ed-l[i].st); } for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) if(abs(l[i].v^l[j].v)>eps) p.push_back(get_inter(l[i],l[j])); sort(p.begin(),p.end()); p.erase(unique(p.begin(),p.end()),p.end()); for(int i=0;i<n;i++) { vector<double>dis; point d=l[i].v.unit(); for(int j=0;j<n;j++) if(abs(l[i].v^l[j].v)>eps) { point inter=get_inter(l[i],l[j]); dis.push_back((inter-l[i].st)*d); } sort(dis.begin(),dis.end()); dis.erase(unique(dis.begin(),dis.end()),dis.end()); for(int j=1,sz=dis.size();j<sz;j++) { int a=get_id(l[i].st+d*dis[j]); int b=get_id(l[i].st+d*dis[j-1]); add(a,b),add(b,a); } } for(int i=0,sz=p.size();i<sz;i++) { vector<pair<double,int> >P; for(int e=first[i];e!=-1;e=nxt[e]) P.push_back(make_pair((p[to[e]]-p[i]).ang(),e)); sort(P.begin(),P.end()); for(int j=0,sz=P.size();j<sz;j++) nxte[P[(j+1)%sz].second^1]=P[j].second; }}void work(){ for(int i=0;i<=tot;i++) { if(vis[i])continue; stack<int>s; s.push(i),vis[i]=true; int j=nxte[i]; while(!vis[j]) { if(!s.empty()&&(s.top()^1)==j)s.pop(); else s.push(j); vis[j]=true; j=nxte[j]; if(j==-1)break; } if(i==j) { double area=0; while(!s.empty()) { area+=(p[to[s.top()^1]]^p[to[s.top()]]); s.pop(); } area*=0.5; if(area>0)ans.push_back(area); } }}int main(){ //freopen("lx.in","r",stdin); Init(); work(); printf("%d\n", ans.size()); sort(ans.begin(), ans.end()); for(int i=0,sz=ans.size();i<sz;++i) printf("%.4lf\n",ans[i]); return 0;}
阅读全文