分析:
本题是求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;
}
就暂时抄写了一遍,留着慢慢理解吧。