UVA LA3218 找边界,PSLG

分析:

本题是求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;
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值