政府想修建一个新的公路网,共 2*N 个城市,目前已经完成 N 条公路,每条公路都是用直线连接两个城市,且没有两条路有公共点包括没有公共端点。
你的任务是再修建 N-1 条路,且需要满足以下三个条件:
每一条路都必须是用一条直线连接两个城市。
如果两条路(包括新路与旧路、新路与新路之间)有一个公共点,则该点必须是道路的端点。
新路和旧路共同组成的公路网能连接所有城市,即每对城市都有一条由连接两个城市的路段组成的道路。
首先为了避免斜率正无穷这种极端情况的出现,可以将点进行一个旋转。 ( x , y ) (x,y) (x,y) 逆时针转 α \alpha α 角后的坐标是 ( x cos α − y sin α , x sin α + y cos α ) (x\cos\alpha-y\sin\alpha,x\sin\alpha+y\cos\alpha) (xcosα−ysinα,xsinα+ycosα)。
计算几何题中出现线段需要统计一些结果的,一般使用扫描线来完成。
假设扫描线从左往右扫。扫描过程中,扫描线会不断被给出的线段分割成若干个区域。当扫描线碰到某条线段的左端点时,说明此时又新增了一个区域。那么我们找出此前该区域内 x x x 坐标最大的点,与当前点连边即可。注意更新各区域的 x x x 坐标最大的点。
当扫到线段的右端点时,就将两个区域合并,同时更新一下最大的 x x x 坐标。
具体过程可以用 set \text{set} set 来实现。
#include<set>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define N 100050
#define inf 10000000000
#define ldb long double
using namespace std;
int n;
ldb nowx;
ldb Pi=acos(-1.0),alpha=Pi*(1.0*139/180),cosal=cos(alpha),sinal=sin(alpha);
struct po
{
int rlx,rly;
ldb x,y;
void calc()
{
x=cosal*rlx-sinal*rly;
y=cosal*rly+sinal*rlx;
}
}a[N<<1];
struct px
{
int id,tp;
ldb x;
}c[N<<1];
struct line
{
int st,ed;mutable int pre;
ldb k,b;
void calc()
{
k=(a[st].y-a[ed].y)/(a[st].x-a[ed].x);
b=a[st].y-k*a[st].x;
}
bool operator <(const line x) const {return k*nowx+b<x.k*nowx+x.b;};
}now;
set<line> S;
set<line>::iterator it;
bool cmp(px x,px y) {return x.x<y.x;}
int main()
{
freopen("network.in","r",stdin);
freopen("network.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=2*n;i+=2)
{
scanf("%d%d",&a[i].rlx,&a[i].rly);a[i].calc();
scanf("%d%d",&a[i+1].rlx,&a[i+1].rly);a[i+1].calc();
if (a[i].x>a[i+1].x) swap(a[i],a[i+1]);
c[i].x=a[i].x;c[i].id=i;c[i].tp=1;
c[i+1].x=a[i+1].x;c[i+1].id=i+1;c[i+1].tp=0;
}
sort(c+1,c+2*n+1,cmp);
now.st=-2;now.ed=0;now.pre=0;now.k=0;now.b=-inf;S.insert(now);
now.st=-1;now.ed=0;now.pre=0;now.k=0;now.b=inf;S.insert(now);
for (int i=1;i<=2*n;++i)
{
nowx=c[i].x;
if (c[i].tp)
{
now.pre=now.st=c[i].id;now.ed=c[i].id+1;
now.calc();
it=S.insert(now).first;--it;
if (it->pre) printf("%d %d %d %d\n",a[it->pre].rlx,a[it->pre].rly,a[now.st].rlx,a[now.st].rly);
it->pre=now.st;
}
else
{
now.st=c[i].id-1;now.ed=c[i].id;
now.calc();
it=S.find(now);--it;
it->pre=now.ed;
S.erase(now);
}
}
return 0;
}