poj2284

本文详细探讨了POJ2284这道计算几何题目,通过实例解析题意,阐述了解题思路和算法实现,涵盖了计算几何中的关键概念,帮助读者深入理解并解决此类问题。
摘要由CSDN通过智能技术生成
/*题意若干线段相交,求平面被分成几个区域
利用欧拉公式:n-m+r==2
n为线段相交的点数,m为线段数量,r为平面被分成的区域数量
r==2+m-n,只要找出交点数n以及线段数m即可。
*/
#include <iostream>
#include <math.h>
#include <algorithm>
using namespace std;
const double pi=acos(-1.0);
const double eps=1e-10;
int cmp(double x)//判断一个数的大小
{
	if(fabs(x)<eps)return 0;
	if(x>0)return 1;
	return -1;
}
struct point
{
	double x,y;
	point(double a=0.0,double b=0.0){x=a,y=b;}
	friend point operator + (const point &a,const point &b){
		return point(a.x+b.x,a.y+b.y);}
	friend point operator - (const point &a,const point &b){
		return point(a.x-b.x,a.y-b.y);}
	friend bool operator == (const point &a ,const point &b){//bool类型
		return cmp(a.x-b.x)==0&&cmp(a.y-b.y)==0;}
	friend point operator * (const point &a ,const double &b){//b为double
		return point(a.x*b,a.y*b);}
	friend point operator * (const double &a ,const point &b){//a为double
		return point(a*b.x,a*b.y);}
	friend point operator / (const point &a ,const double &b){//b为double
		return point(a.x/b,a.y/b);}
	double norm(){//求距离
		return sqrt(x*x+y*y);}
};
double det(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;
}
struct line   //利用线段a-b代表直线,可直线可线段
{
	point a,b;
	line(point x,point y):a(x),b(y){}//!!!此处
};
bool pointOnsegment(point p,line l)//点p是否在线段l上
{
	point s=l.a,t=l.b;
	return cmp(det(p-s,t-s))==0&&cmp(dot(p-s,p-t))<=0;
}
bool parallel(line a,line b)//直线a和直线b是否平行
{
	return !cmp(det(a.a-a.b,b.a-b.b));
}
bool line_make_point(line a,line b,point &res)//求直线a-b的交点
{
	if(parallel(a,b)) return 0;
	double s1=det(a.a-b.a,b.b-b.a);
	double s2=det(a.b-b.a,b.b-b.a);
	res=(s1*a.b-s2*a.a)/(s1-s2);
	return 1;
}
bool segment_make_point(line a,line b,point &res)  //线段a,b交点
{
	if(line_make_point(a,b,res))
		return pointOnsegment(res,a)&&pointOnsegment(res,b);
	return false;
}
const int maxn=100000;
point p[maxn];
point jiaodian[maxn];
bool cmp1(point a,point b)
{
	if(a.x-b.x)
		return a.x<b.x;
	return a.y<b.y;
}
int main()
{
	int n,m,N,cas=1;
	while(cin>>N,N)
	{
		n=0;
		m=0;
		for(int i=0;i<N;i++)
			cin>>p[i].x>>p[i].y;
		for(int i=0;i<N;i++)//枚举个条边,寻找交点
			for(int j=0;j<N;j++)
			{
				line l1(p[i],p[(i+1)%N]);
				line l2(p[j],p[(j+1)%N]);
				point res;
				if(segment_make_point(l1,l2,res))  //端点也属于交点,也加入jiaodian[]
					jiaodian[n++]=res;
			}
			sort(jiaodian,jiaodian+n,cmp1);  //排序
			n=unique(jiaodian,jiaodian+n)-jiaodian;//删除重复顶点
			for(int i=0;i<n;i++)  //枚举交点,若交点在某线段上,则把线段一分为二。
				for(int j=0;j<N;j++)
				{
					line l(p[j],p[(j+1)%N]);
					if(pointOnsegment(jiaodian[i],l)&&!(l.a==jiaodian[i]))//  !(l.a==jiaodian[i])防止重复出现
						m++;
				}
				printf("Case %d: There are %d pieces.\n",cas++,2+m-n);

	}
	return 0;
}
/*
5
0 0 0 1 1 1 1 0 0 0
7
1 1 1 5 2 1 2 5 5 1 3 5 1 1
Case 1: There are 2 pieces.
Case 2: There are 5 pieces.*/


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值