UVA 1342 That Nice Euler Circuit(二维几何基础)
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=528&page=show_problem&problem=4088
题意:
平面上有一个包含n个端点的一笔画,第n个端点总是和第1个端点重合,因此图案是一个闭合曲线.组成一笔画的各个线段可以相交,但是不会部分重叠.求平面被该一笔画分成了多少部分?
分析:
刘汝佳<<训练指南>>P260例题.
首先由欧拉定理 点-边+面=2. 所以我们只要求出该平面内的所有点和线段(边)数,就可以算出该平面被分成了多少部分.
那么我们先求所有的交点(不算n个端点,端点另外再加,所以这些交点一定是在线段内部的,即刘汝佳所说的规范相交):
由于一共n条线段,且任意线段不会部分重叠,所以任意两条线段要不平行(不相交)要不就规范相交. 所以我们只需要枚举所有的线段,然后求出他们规范相交的节点保存在数组中即可.
然后我们再把原本的n-1个顶点(起点与终点相同不用都加)加进去,然后去重.
下面我们要知道该平面一共有多少条线段,那么我们只要知道原来的每条线段到底被分成了多少段即可. 对于原来的每条线段,我们用上面求得的所有点去判断,当前这个点是不是在该线段内(不包含端点),如果该点在线段内,那么就说明该线段被该点截断,多出来1段.所以总的线段数目在n的基础上要+1.
最终求出了点和线段数,平面数= 边+2-点.
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps =1e-10;
int dcmp(double x)
{
if(fabs(x)<eps) return 0;
return x<0?-1:1;
}
struct Point
{
double x,y;
Point(){}
Point(double x,double y):x(x),y(y){}
bool operator<(const Point &b)const
{
return x<b.x||(x==b.x && y<b.y);
}
bool operator==(const Point &b)const
{
return dcmp(x-b.x)==0 && dcmp(y-b.y)==0;
}
};
typedef Point Vector;
Vector operator +(Vector A,Vector B)
{
return Vector(A.x+B.x, A.y+B.y);
}
Vector operator -(Point A,Point B)
{
return Vector(A.x-B.x, A.y-B.y);
}
Vector operator *(Vector A,double p)
{
return Vector(A.x*p, A.y*p);
}
Vector operator /(Vector A,double p)
{
return Vector(A.x/p, A.y/p);
}
double Dot(Vector A,Vector B)
{
return A.x*B.x+A.y*B.y;
}
double Length(Vector A)
{
return sqrt(Dot(A,A));
}
double Angle(Vector A,Vector B)
{
return acos(Dot(A,B)/Length(A)/Length(B));
}
double Cross(Vector A,Vector B)
{
return A.x*B.y-A.y*B.x;
}
bool SegmentProperIntersection(Point a1,Point a2,Point b1,Point b2)//判断线段规范相交
{
double c1=Cross(a2-a1,b1-a1),c2=Cross(a2-a1,b2-a1);
double 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)//判断点P是否在选段a1a2内
{
return dcmp( Cross(a1-P,a2-P) )==0 && dcmp(Dot(a1-P,a2-P))<0;
}
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w)//求直线交点
{
Vector u=P-Q;
double t=Cross(w,u)/Cross(v,w);
return P+v*t;
}
/***以上为刘汝佳模板***/
const int maxn=90000+5;
Point p[maxn];//原始点
Point v[maxn];//所有点
int main()
{
int n;
int kase=0;
while(scanf("%d",&n)==1 && n)
{
int point_num=n-1;//点数目
int edge_num=n-1;//边数目
for(int i=0;i<n;++i)
{
scanf("%lf%lf",&p[i].x,&p[i].y);
v[i]=p[i];
}
--n;
//求线段两两相交的交点
for(int i=0;i<n;++i)
for(int j=i+1;j<n;++j)
{
Point &a1=p[i];
Point &a2=p[(i+1)%n];
Point &b1=p[j];
Point &b2=p[(j+1)%n];
if(SegmentProperIntersection(a1,a2,b1,b2))
{
v[point_num++]=GetLineIntersection(a1,a2-a1,b1,b2-b1);
}
}
sort(v,v+point_num);
point_num = unique(v,v+point_num)-v;
for(int i=0;i<n;++i)//原始线段
for(int j=0;j<point_num;++j)//遍历所有点
{
if(OnSegment(v[j],p[i],p[(i+1)%n])) ++edge_num;//若该点在该线段内部
}
printf("Case %d: There are %d pieces.\n",++kase,edge_num+2-point_num);
}
return 0;
}
分享到:
相关推荐
二维欧拉方程计算,包含Roe和Rotated-RHLL格式
二维Euler方程的Jameson求解方法.doc
基于结构网格二维Euler方程的Jameson求解方法
求解二维Euler方程的流场求解器,可以计算二维翼型流场,编程语言采用Fortran,网格为非结构网格,空间里县采用jamson中心格式,时间离散采用四步龙格库塔显式时间离散,
本程序利用五阶WENO格式结合Lax-Friedrichs矢通量分裂法求解二维Euler 方程(u_t = RHS = -f(u)_x - g(u)_y)的空间项,应用三阶TVD Runge-Kutta法 求解其时间项来模拟Riemann间断问题.
二维可压缩Euler方程求解器-matlab版本
求解一维Euler方程的代码,采用无反射边界条件。
python code for Euler project asdfasdf asdfasdf aefa efae fds fsdaf
二维双极Euler-Poisson方程的稳定解的存在性,黎野平,周钢,本文研究了二维双极Euler-Poisson方程. 该方程用来描述半导体和等离子体里粒子的运动. 在合适的边值条件下,使用精细的能量估计和Schaude
Euler and 改进Euler 算法
一维热传导方程的前向Euler和紧差分格式
基于vs实现,用基本欧拉操作算法构建的三维几何体,导出obj文件,适合新手学习。
大数据-算法-在非结构自适应网格上对二维Euler方程进行数值模拟.pdf
欧拉 二维Euler非结构化网格
利用roe格式采用三阶龙格库塔时间推进格式求解一维欧拉方程
欧拉FV 二维非结构化有限体积Euler方程求解器
在解微分方程数值解的问题上Euler公式与改进Euler比较,改进的Euler公式精确度高。
使用openEuler操作系统;2;如何登陆Linux ;远程登录 默认情况下openEuler支持远程登录,也可以进行修改; 可以通过putty、xshell等工具远程登录到openEuler。;5;6;Linux用户;bash shell快捷的操作;谢谢
华为欧拉系统 EulerOS-V2.0SP5-x86_64-dvd...EulerOS是华为自主研发的服务器操作系统,能够满足客户从传统IT基础设施到云计算服务的需求。EulerOS对ARM64架构提供全栈支持,打造完善的从芯片到应用的一体化生态系统。