UVA LA3218 找边界,PSLG

来源:互联网 发布:天庭淘宝店 宁小北txt 编辑:程序博客网 时间:2024/06/10 20:23

分析:

本题是求PSLG得外轮廓,需要借助与前面所说的“类似卷包裹”的算法。具体来说,首先找到x坐标最小的点(如果有多个,找y坐标最小的点),然后开始“卷包裹”。

首先找到初始边。

然后每次都执行如下操作。

首先看看当前线段是否和其他线段相交(根据题意,一定是规范相交),如果不想交,说明可以直接走到当前线段的终点,否则走到最近的交点就得停下来,接下来转弯

并继续前进。转弯时如果有多条路可以走,选择那条右转的最厉害的线段。转回原点以后,整个过程结束。

这题代码比较繁琐,不容易懂,看了大牛的代码看了好久也没完全理解,

lower_bound()函数讲解:

函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置

举例如下:

一个数组number序列为:4,10,11,30,69,70,96,100.设要插入数字3,9,111.pos为要插入的位置的下标

pos = lower_bound( number, number + 8, 3) - number,pos = 0.即number数组的下标为0的位置。

pos = lower_bound( number, number + 8, 9) - number, pos = 1,即number数组的下标为1的位置(即10所在的位置)。

pos = lower_bound( number, number + 8, 111) - number, pos = 8,即number数组的下标为8的位置(但下标上限为7,所以返回最后一个元素的下一个元素)。

所以,要记住:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!~

返回查找元素的第一个可安插位置,也就是“元素值>=查找值”的第一个元素的位置



#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>#include<cctype>#include<string>#include<set>#include<map>#include<queue>#include<stack>#include<vector>using namespace std;const double eps=1e-6;int dcmp(double x){    if(fabs(x)<eps) return 0;    return x>0?1:-1;    //return fabs(x) < eps ? 0 : (x > 0 ? 1 : -1);}struct point{  double x;  double y;  point(){}  point(double x,double  y):x(x),y(y){}  void in()  {      cin>>x>>y;  }  void out()  {      cout<<x<<' '<<y<<endl;  }  point operator + (const point &t) const  {      return point(x+t.x,y+t.y);  }  point operator - (const point &t) const  {      return point(x-t.x,y-t.y);  }  point operator * (const double &t) const  {      return point(x*t,y*t);  }  point operator / (const double &t) const  {      return point(x/t,y/t);  }  bool operator < (const point &t) const  {      return (dcmp(x-t.x)<0||(dcmp(x-t.x)==0&&dcmp(y-t.y)<0));  }  bool operator == (const point &t) const  {      return dcmp(x-t.x) ==0 &&dcmp(y-t.y)==0;  }};double cross(point a,point b){    return a.x*b.y-a.y*b.x;}double dot(point a,point b){    return a.x*b.x+a.y*b.y;}double length(point a){    return sqrt(dot(a,a));}point nomal(point t){    double l=length(t);    return  point(-t.y/l,t.x/l);}struct line{    point p;    point v;    double ang;    line() {}    line(point p,point v):p(p),v(v){        ang=atan2(v.y,v.x);    }    bool operator < (const line &l) const    {        return ang<l.ang;    }};bool onleft(line l,point p){    return cross(l.v,p-l.p)>0;}point getintersection(line a,line b){    point u=a.p-b.p;    double t=cross(b.v,u)/cross(a.v,b.v);    return a.p+a.v*t;}bool sgementproperintersection(point a1,point a2,point b1,point b2){    double c1=cross(a2-a1,b1-a1),c2=cross(a2-a1,b2-a1),           c3=cross(b2-b1,a1-b1),c4=cross(b2-b1,a2-b1);    return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0;}bool onsegment(point p,point a1,point a2){    return dcmp(cross(a1-p,a2-p))==0&&dcmp(dot(a1-p,a2-p))<0;}typedef vector<point> Polygon;double PolygonArea(Polygon poly){    double area=0;    int n=poly.size();    for(int i=1;i<n-1;i++)    {        area+=cross(poly[i]-poly[0],poly[(i+1)%n]-poly[0]);    }    return area/2;}struct Edge{    int from;    int to;    double ang;};const int maxn=10000+10;struct PSLG{    int n,m,face_cnt;    double x[maxn],y[maxn];    vector<Edge> edges;    vector<int> G[maxn];    int vis[maxn*2];    int left[maxn*2];    int prev[maxn*2];    vector<Polygon> faces;    double area[maxn];    void init(int n)    {        this->n=n;        for(int i=0;i<n;i++)        {            G[i].clear();        }        edges.clear();        faces.clear();    }    double getAngle(int from,int to)    {        return atan2(y[to]-y[from],x[to]-x[from]);    }    void AddEdge(int from,int to)    {        edges.push_back((Edge) {from,to,getAngle(from,to)});        edges.push_back((Edge) {to,from,getAngle(to,from)});        m=edges.size();        G[from].push_back(m-2);        G[to].push_back(m-1);    }    void Build()    {        for(int u=0;u<n;u++)        {            int d=G[u].size();            for(int i=0;i<d;i++)                for(int j=i+1;j<d;j++)            {                if(edges[G[u][i]].ang>edges[G[u][j]].ang)                    swap(G[u][i],G[u][j]);            }            for(int i=0;i<d;i++)            {                prev[G[u][(i+1)%d]]=G[u][i];            }        }        memset(vis,0,sizeof(vis));        face_cnt=0;        for(int u=0;u<n;u++)        {            for(int i=0;i<G[u].size();i++)            {                int e=G[u][i];                if(!vis[e])                {                    face_cnt++;                    Polygon poly;                    for(;;)                    {                        vis[e]=1;                        left[e]=face_cnt;                        int from=edges[e].from;                        point P(x[from],y[from]);                        poly.push_back(P);                        e=prev[e^1];                        if(e==G[u][i]) break;                    }                    faces.push_back(poly);                }            }        }        for(int i=0;i<face_cnt;i++)        {            area[i]=PolygonArea(faces[i]);        }    }};PSLG g;const int maxp=100+5;point P[maxp];point V[maxp*(maxp-1)/2+maxp];int n,c;int ID(point p){    return lower_bound(V,V+c,p)-V;}Polygon simplify(const Polygon &poly) //去共线{    Polygon ans;    int n=poly.size();    for(int i=0;i<n;i++)    {        point a=poly[i];        point b=poly[(i+1)%n];        point c=poly[(i+2)%n];        if(dcmp(cross(b-a,c-b))!=0)           {               ans.push_back(b);           }    }    return ans;}void build_graph(){    for(int i=0;i<n;i++)    {        V[i]=P[i];    }    vector<double> dist[maxp];    c=n;    for(int i=0;i<n;i++)        for(int j=i+1;j<n;j++)    {        if(sgementproperintersection(P[i],P[(i+1)%n],P[j],P[(j+1)%n]))        {            point ip=getintersection(line(P[i],P[(i+1)%n]-P[i]),line(P[j],P[(j+1)%n]-P[j]));            V[c++]=ip;            dist[i].push_back(length(ip-P[i]));            dist[j].push_back(length(ip-P[j]));        }    }    sort(V,V+c);    c=unique(V,V+c)-V;    g.init(c);    for(int i=0;i<c;i++)    {        g.x[i]=V[i].x;        g.y[i]=V[i].y;    }    for(int i=0;i<n;i++) //按在那条边上来统计    {        point v=P[(i+1)%n]-P[i];        double len=length(v);        v=v/len;        dist[i].push_back(0);        dist[i].push_back(len);        sort(dist[i].begin(),dist[i].end());        int sz=dist[i].size();        for(int j=1;j<sz;j++)        {            point a=P[i]+v*dist[i][j-1];            point b=P[i]+v*dist[i][j];            if(a==b) continue;            g.AddEdge(ID(a),ID(b));        }    }    g.Build();}int main(){    while(cin>>n&&n)    {        for(int i=0;i<n;i++)            cin>>P[i].x>>P[i].y;        build_graph();        Polygon poly;        for(int i=0;i<g.faces.size();i++)        {            if(g.area[i]<0)            {                poly=g.faces[i];                reverse(poly.begin(),poly.end());                poly=simplify(poly);                break;            }        }        int start=0;        int m=poly.size();        cout<<m<<endl;        for(int i=0;i<m;i++)        {            if(poly[i]<poly[start])            {                start=i;            }        }        for(int i=start;i<m;i++)        {            printf("%.4f %.4f\n",poly[i].x,poly[i].y);        }        for(int i=0;i<start;i++)        {            printf("%.4f %.4f\n",poly[i].x,poly[i].y);        }    }    return 0;}

就暂时抄写了一遍,留着慢慢理解吧。

0 0
原创粉丝点击