LA3218 Find the Border
题意
分析
虽然只找外轮廓,但是时间复杂度不比PSLG优秀,所以可以当做联系PSLG的题做。
PSLG框架
- 找出所有交点
- 交点按序连边
- 把边按极角序排序
- 逆时针找圈
然后何以会顺时针找出无限区域的边呢?缘于这一段:
for(int i=0;i<d;++i)
prev[G[u][(i+1)%d]]=G[u][i];
边prev连向极角序次小的。极角序最小的边的prev连向极角序最大的。
然后在边界上就会顺时针找下去。但是在内部的时候这些边无疑会被逆时针遍历到,所以没有影响。
于是找出无限区域的轮廓的特殊性在于它的有向面积是负的。
时间复杂度主要是找轮廓时遍历边的\(O(n^2)\)
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<ctime>
#include<cstring>
#define rg register
#define il inline
#define co const
template<class T>il T read()
{
rg T data=0;
rg int w=1;
rg char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
{
data=data*10+ch-'0';
ch=getchar();
}
return data*w;
}
template<class T>T read(T&x)
{
return x=read<T>();
}
using namespace std;
typedef long long ll;
co double eps=1e-8;
int dcmp(double x)
{
return fabs(x)<eps?0:(x<0?-1:1);
}
struct Point
{
double x,y;
Point(double x=0,double y=0)
:x(x),y(y){}
bool operator<(co Point&p)co
{
return dcmp(x-p.x)<0||(dcmp(x-p.x)==0&&dcmp(y-p.y)<0);
}
bool operator==(co Point&p)co
{
return dcmp(x-p.x==0)&&dcmp(y-p.y)==0;
}
};
typedef Point Vector;
Vector operator+(co Vector&A,co Vector&B)
{
return Vector(A.x+B.x,A.y+B.y);
}
Vector operator-(co Vector&A,co Vector&B)
{
return Vector(A.x-B.x,A.y-B.y);
}
Vector operator*(co Vector&A,double p)
{
return Vector(A.x*p,A.y*p);
}
double Dot(co Vector&A,co Vector&B)
{
return A.x*B.x+A.y*B.y;
}
double Cross(co Vector&A,co Vector&B)
{
return A.x*B.y-A.y*B.x;
}
double Length(co Vector&A)
{
return sqrt(Dot(A,A));
}
typedef vector<Point> Polygon;
Point LineLineIntersection(co Point&P,co Vector&v,co Point&Q,co Vector&w)
{
Vector u=P-Q;
double t=Cross(w,u)/Cross(v,w);
return P+v*t;
}
bool SegmentProperIntersection(co Point&a1,co Point&a2,co Point&b1,co 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(co Point&p,co Point&a1,co Point&a2)
{
return dcmp(Cross(a1-p,a2-p))==0&&dcmp(Dot(a1-p,a2-p))<0;
}
double PolygonArea(co 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,to;
double ang;
};
co int MAXN=1e4;
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 Angle(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,Angle(from,to)});
edges.push_back((Edge){to,from,Angle(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];
}
fill(vis,vis+m,0);
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;
poly.push_back(Point(x[from],y[from]));
e=prev[e^1];
if(e==G[u][i])
break;
assert(vis[e]==0);
}
faces.push_back(poly);
}
}
for(int i=0;i<faces.size();++i)
{
area[i]=PolygonArea(faces[i]);
}
}
}g;
co int MAXP=100;
int n,c;
Point P[MAXP];
Point V[MAXP*(MAXP-1)/2+MAXP];
int ID(Point P)
{
return lower_bound(V,V+c,P)-V;
}
Polygon Simplify(co Polygon&poly)
{
Polygon ans;
int n=poly.size();
for(int i=0;i<n;++i)
{
co Point&a=poly[i];
co Point&b=poly[(i+1)%n];
co Point&c=poly[(i+2)%n];
if(dcmp(Cross(a-b,c-b))!=0)
ans.push_back(b);
}
return ans;
}
void BuildGraph()
{
c=n;
for(int i=0;i<n;++i)
V[i]=P[i];
vector<double>dist[MAXP];
for(int i=0;i<n;++i)
for(int j=i+1;j<n;++j)
if(SegmentProperIntersection(P[i],P[(i+1)%n],P[j],P[(j+1)%n]))
{
Point p=LineLineIntersection(P[i],P[(i+1)%n]-P[i],P[j],P[(j+1)%n]-P[j]);
V[c++]=p;
dist[i].push_back(Length(p-P[i]));
dist[j].push_back(Length(p-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)
{
Vector v=P[(i+1)%n]-P[i];
double len=Length(v);
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]/len);
Point b=P[i]+v*(dist[i][j]/len);
if(a==b)
continue;
g.AddEdge(ID(a),ID(b));
}
}
g.Build();
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 m=poly.size();
printf("%d\n",m);
int start=0;
for(int i=0;i<m;++i)
if(poly[i]<poly[start])
start=i;
for(int i=start;i<m;++i)
printf("%.4lf %.4lf\n",poly[i].x,poly[i].y);
for(int i=0;i<start;++i)
printf("%.4lf %.4lf\n",poly[i].x,poly[i].y);
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;++i)
{
int x,y;
read(x),read(y);
P[i]=Point(x,y);
}
BuildGraph();
}
return 0;
}
LA3218 Find the Border的更多相关文章
- 理解CSS边框border
前面的话 边框是CSS盒模型属性中默默无闻的一个普通属性,CSS3的到来,但得边框属性重新焕发了光彩.本文将详细介绍CSS边框 基础样式 边框是一条以空格分隔的集合样式,包括边框粗细(边框宽度 ...
- css样式之border
border用法详解: 1.border-width 属性设置边框的宽度 可能的值:像素 2.border-style 属性设置边框的样式 可能的值:solid(直线),dashed(虚线),dott ...
- 通过CSS的border绘制三角形
通过css的border 可以绘制出三角形, 不同的样式组合,有着不同的效果,可以控制它的大小,颜色,方向.看下面各种图形,相信可能还有很多图形,大家都没见过. 先写出公共的样式: .border { ...
- css3学习--border
http://blog.sina.com.cn/s/blog_61671b520101gelr.html border-radius border-radius: 50px 20px;上下都是50px ...
- border:none 和border:0区别差异
border:none与border:0的区别体现为两点:一是理论上的性能差异,二是浏览器兼容性的差异. 性能差异: [border:0;]把border设为“0”像素效果等于border-width ...
- WPF 通过Border来画边框
WPF有自己的表格控件DataGrid.ListBox等,如果只是简单的需求,可以通过Border控件来画边框. 比如我们需要给上面的控件加上边框. <Window x:Class=" ...
- css border属性做小三角标
<!doctype html><html> <head> <title></title> <meta charset="ut ...
- 使用border做三角形
网站上经常会使用一些三角形,除了图片的方式,实际上利用border我们可以做出纯CSS的三角形.我们知道border是个边抖可以单独设置,当四个边相交的时候他们是什么时候改变的? .t0{ margi ...
- iPhone 6/plus iOS Safari fieldset border 边框消失
问题:iPhone6 plus 手机浏览网页,fieldset border 边框消失. 示例代码: <div> <fieldset style="border: 1px ...
随机推荐
- mysql DATE_FORMAT 年月日时分秒格式化
SELECT DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i:%s')
- Ubuntu 1210怎么获得root权限登录
Ubuntu 12.10 怎么用Root 登录?以下是Ubuntu 12.10 启用Root 登录的方法吗,希望对大家有些帮助吧! 方法如下: 1.先设定一个 Root 密码 sudo passwd ...
- ssm框架搭建流程及原理分析
这几天自己想搭建个ssm框架玩一下,有些东西长时间不玩都给忘了,所以自己把整个流程整理了一下,只要跟着步骤,就能顺利完成ssm框架的搭建. 一.搭建步骤: 1.整理jar包 2.对于一个web ...
- 异步编程——promise
异步编程--promise 定义 Promise是异步编程的一个解决方案,相比传统的解决方法--回调函数,使用Promise更为合理和强大,避免了回调函数之间的层层嵌套,也使得代码结构更为清晰,便于维 ...
- python学习笔记(xlwt/xlrd下载安装)
python支持处理Excel 可以使用xlwt xlrd 模块 分别在https://pypi.python.org/pypi/xlwt 和 https://pypi.python.org/pyp ...
- python学习笔记(unittest)
刚刚放假回来我想很多人都还没有缓过来吧 这次介绍一个python自带的测试框架 unitest #!/usr/bin/env python # -*- coding: utf_8 -*- import ...
- RabbitMQ C# driver stops receiving messages
http://stackoverflow.com/questions/12499174/rabbitmq-c-sharp-driver-stops-receiving-messages
- poj2723 2-sat
当两个门锁相同时,这个钥匙必须用,不同时分开用 可以直接遍历门,当然二分更快 #include<map> #include<set> #include<cmath> ...
- 解决tomcat中jdk1.5运行日志相差8小时问题
tomcat运行日志时间与电脑中的时间相差8小时,原因是因为jdk1.5的原因: 解决办法是在jdk运行的时候加上默认参数: Window->Preferences->Java->I ...
- DDOS工具合集---CC 2.0(僵尸网络proxy,单一url,可设置cookie,refer),传奇克星(代理+单一url,可设置cookie),NetBot_Attacker网络僵尸1.0(僵尸网络,HTTP NO-Cache Get攻击模式,CC攻击,HTTP空GET请求攻击),傀儡僵尸VIP1.4版(僵尸网络,动态单一url)、上兴网络僵尸2.3、中国制造网络僵尸、安全基地网络僵尸==
DDOS工具合集 from:https://blog.csdn.net/chinafe/article/details/74928587 CC 著名的DDOS CC工具,效果非常好!CC 2.0使用了 ...