sgu129:Inheritance

题目大意就是给出一个凸多边形,再给出一些线段,求出每条线段在多边形内部的长度。

首先把给出的点按极角排序,求出这个凸多边形。

关键是怎样判断一条线段是否与多边形相交,交点,以及内部的长度。

判断一条线段是否与多边形相交,即判断其与多边形每条边是否有交点。

引理:若线段AB与线段CD相交,那么A、B分别在CD两侧,C、D分别在AB两侧,反之成立。

判断两个点分别在线段两侧,我们可以用叉积,即若(CA×CD)*(CB×CD)<=0时,A、B在CD两侧(或AB与CD共线)。

当(CA×CD)*(CB×CD)==0 && (AC×AB)*(AD×AB)==0时,AB与CD共线,这种情况要排除,不算交点。

若线段相交,用点法式表示两条直线为(P,v)、(Q,w),前一项为直线上一点,后一项为方向向量,即直线上任意一点都可以表示为P+t*v。

设u=P-Q,k=cross(w,u)/cross(v,w),则交点为P+k*v(白书上的...)。

把这些交点存入数组中,由于多边形顶点会被计算两次,所以要去重。

求出交点的同时,我们还要判断要求的线段两端点是否在多边形内部,同样用叉积就好了,对每条线段依次判断。

求出以上内容后,输出也要注意点细节:

(端点在线段上不算在多边形内)

当两端点都在多边形内部时,直接计算线段长度;

当有一端点在多边形内部时,计算在内部的那个点和交点的距离;

当线段与多边形有两交点时,计算两交点的距离;

输出0。

over,其实这道题坑的就是细节稍多额,wa了很多次......

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAXN = 405;
const double MAXL = 30005;

int N, M;
struct Point 
{ 
	double x, y; 
}v[MAXN], ta, tb;

int minf;
Point operator - (const Point &A, const Point &B)
{
  	Point tmp = {A.x-B.x, A.y-B.y};
  	return tmp;	
}
Point operator + (const Point &A, const Point &B)
{
  	Point tmp = {A.x+B.x, A.y+B.y};
  	return tmp;	
}
Point operator * (const double &A, const Point &B)
{
  	Point tmp = {A*B.x, A*B.y};
  	return tmp;	
}
bool operator == (const Point &A, const Point &B)
{
  	return (A.x == B.x && A.y == B.y);
}
double time(Point A, Point B)
{
  	return A.x*B.y-A.y*B.x;	
}

int find()
{
  	int re = 1;
  	for(int i = 0; i < N; ++i)
    	if(v[re].x > v[i].x || (v[re].x == v[i].x && v[re].y > v[i].y)) re = i;
  	return re;
}

bool cmp(const Point &A, const Point &B)
{
  	return (time(v[0]-A, v[0]-B) > 0);
}
bool vcmp (const Point &A, const Point &B) 
{
	return (A.x < B.x || (A.x == B.x && A.y < B.y)); 
}

Point get(Point P, Point v, Point Q, Point w)
{
	Point u = P-Q;
	double t = time(w, u)/time(v, w);
	return P+t*v;	
}

Point p = {0, 0};
bool online = false;
bool intersect(Point A, Point B, Point C, Point D)
{
	double c1 = time(B-A, C-A), c2 = time(B-A, D-A), c3 = time(D-C, A-C), c4 = time(D-C, B-C);
	if(c1 == 0 && c2 == 0) { online = true;return false; }
	if(c1*c2 <= 0 && c3*c4 <= 0)
	{
		p = get(A, B-A, C, D-C);
		return true;
	}
	else return false;
}

double dis(const Point &A, const Point &B)
{
	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

double solve()
{
  	Point inter[4] = {-MAXL, -MAXL, -MAXL, -MAXL}, real[2] = {-MAXL, -MAXL};
  	int top = 0, topr = 0;
  	bool a = true, b = true;
  	online = false;
  	for(int i = 0, j = N-1; i < N; j = i++)
  	{
  		if(a && time(v[j]-ta, v[i]-ta) <= 0) a = false;
  		if(b && time(v[j]-tb, v[i]-tb) <= 0) b = false;
  		if(intersect(v[j], v[i], ta, tb)) 
			inter[top++] = p; 	
  		if(online) { a = b = top = 0;break; }
  	}
  	sort(inter, inter+top, vcmp);
	for(int i = 0; i < top; ++i)
		if(i && inter[i] == inter[i-1]) continue;
		else real[topr++] = inter[i];
	if(a && b) return dis(ta, tb);
	else if(a) return dis(ta, real[0]);
	else if(b) return dis(tb, real[0]);
	else if(topr == 2) return dis(real[0], real[1]);
	else return 0;
}

int main()
{
  	scanf("%d", &N);
  	for(int i = 0; i < N; ++i)
   		scanf("%lf%lf", &v[i].x, &v[i].y);
  
  	minf = find();
  	swap(v[0], v[minf]);
  	sort(v+1, v+N, cmp);
  
  	scanf("%d", &M);
  	for(int i = 0; i < M; ++i)
  	{	scanf("%lf%lf%lf%lf", &ta.x, &ta.y, &tb.x, &tb.y);	
	  	printf("%.2lf\n", solve());	
	}
  	return 0;	
} 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值