poj 1066 Treasure Hunt

刚开始没有考虑四顶点和各端点的区别,wa了

这次把一些基本函数自己研究透原理了,手打了一遍

/*该题中这种直接由直接构成的多边形一定是凸多边形
因为该题中的线段都是跨越整个正方形的,所以如果从目标点连一条射线出去 ,那么从其他地方绕路过去也必然会经过该线段
本来需要枚举每边界上相邻两点的中点的,但从中点穿过也相当于从端点穿过,所以直接枚举端点就可以了 
*/ 
#include<stdio.h>
#include<math.h>
#include<algorithm> 
using namespace std;
const double EPS=1e-8;
int sgn(double x) {
	if (fabs(x)<EPS) return 0;
	if (x<0) return -1;
	return 1;
} 
struct Point {
	double x,y;
	Point() {}
	Point(double _x,double _y) {
		x=_x;
		y=_y;
	}
	Point operator - (const Point &b) const {
		return Point(x-b.x,y-b.y);
	}
	double operator ^ (const Point &b) const {
		return x*b.y-y*b.x;
	}
};
struct Line {
	Point s,e;
	Line() {}
	Line(Point _s,Point _e) {
		s=_s;
		e=_e;
	}
};
bool inter(Line l1,Line l2) {
	return 
	//快速排斥实验 
	max(l1.s.x,l1.e.x)>=min(l2.s.x,l2.e.x) &&//右界大于左界 
	max(l2.s.x,l2.e.x)>=min(l1.s.x,l1.e.x) && 
	max(l1.s.y,l1.e.y)>=min(l2.s.y,l2.e.y) &&//上界要大于下界 
	max(l2.s.y,l2.e.y)>=min(l1.s.y,l1.e.y) &&
	//跨立实验 
	sgn((l1.s-l2.s)^(l2.e-l2.s))*sgn((l1.e-l2.s)^(l2.e-l2.s))<=0 &&
	sgn((l2.s-l1.s)^(l1.e-l1.s))*sgn((l2.e-l1.s)^(l1.e-l1.s))<=0;
}
Line l[100];
int main() {
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	#endif
	int n;
	double x1,y1,x2,y2;
	Point t;
	scanf("%d",&n);
	for(int i=1;i<=n;i++) {
		scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
		l[i]=Line(Point(x1,y1),Point(x2,y2));
	}
	scanf("%lf%lf",&t.x,&t.y);
	l[n+1]=Line(Point(0,0),Point(0,100));
	l[n+2]=Line(Point(0,100),Point(100,100));
	l[n+3]=Line(Point(100,100),Point(100,0));
	l[n+4]=Line(Point(100,0),Point(0,0));
	Point p;
	int cnt=0;
	int ans=100000;
	for(int i=1;i<=n+4;i++) {
		cnt=0;
		p=l[i].s;
		for(int j=1;j<=n;j++) {
			if (inter(Line(p,t),l[j])) cnt++;
		}
		//因为边界上的点本来就已经在一条线段上了,所以不需要加+1,而四顶点还要加上最后一层强需要的点 
		if (i>n) ans=min(cnt+1,ans);
		else ans=min(cnt,ans);
		cnt=0; 
		p=l[i].e;
		for(int j=1;j<=n;j++) {
			if (inter(Line(p,t),l[j])) cnt++;
		}
		if (i>n) ans=min(cnt+1,ans);
		else ans=min(cnt,ans);
		
	}
	printf("Number of doors = %d\n",ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值