Treasure Hunt POJ - 1066(线段相交+思维)

Treasure Hunt POJ - 1066

题意:在一个框里面,有很多互相交错的线段,问从外面开始往里走,碰到一次线段答案+1,问答案最少是多少就能到达目的地,需要从线段的中点进入。

思路:其实把外围的中点坐标处理出来,然后枚举外围点与目的地连线,穿过的线段数与答案取min就可以了,用这个方法与从中点过其实也没有冲突的,也并不会产生谁更优的策略。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define eps 1e-8
using namespace std;

double 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);
	}
	Point operator - (const Point &b) const {
		return Point(x - b.x,y - b.y);
	}
	double operator * (const Point &b) const {
		return 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;
	}
	
	//线段与线段相交判断
	//2 规范相交
	//1 非规范相交
	//0 不相交
	int seg_cross_seg(Line v){
		int d1 = sgn((e-s)^(v.s-s));
		int d2 = sgn((e-s)^(v.e-s));
		int d3 = sgn((v.e-v.s)^(s-v.s));
		int d4 = sgn((v.e-v.s)^(e-v.s));
		if((d1^d2)==-2&&(d3^d4)==-2) return 2;
		return (d1==0 &&sgn((v.s-s)*(v.s-e))<=0)||
				(d2==0 &&sgn((v.e-s)*(v.e-e))<=0)||
				(d3==0 &&sgn((s-v.s)*(s-v.e))<=0)||
				(d4==0 &&sgn((e-v.s)*(e-v.e))<=0);
	}

} l[33];

int num;
int ecnt = 0, scnt = 0, wcnt = 0, ncnt = 0;
double x[2], y[2], baox, baoy;
double e[33], s[33], w[33], n[33];

void tian(int i) {
	if(x[i] == 0) w[wcnt++] = y[i];
	if(y[i] == 0) s[scnt++] = x[i];
	if(x[i] == 100) e[ecnt++] = y[i];
	if(y[i] == 100) n[ncnt++] = x[i];
}

bool cmp(double a, double b) {
	return a < b;
}

int main() {
	scanf("%d", &num);
	ecnt = 0, scnt = 0, wcnt = 0, ncnt = 0;
	for(int i = 0;i < num; i++) {
		scanf("%lf %lf %lf %lf", &x[0], &y[0], &x[1], &y[1]);
		l[i] = Line(Point(x[0], y[0]), Point(x[1], y[1]));
		tian(0); tian(1);
	}
	scanf("%lf %lf", &baox, &baoy);
	
	e[ecnt++] = 0; e[ecnt++] = 100;
	s[scnt++] = 0; s[scnt++] = 100;
	w[wcnt++] = 0; w[wcnt++] = 100;
	n[ncnt++] = 0; n[ncnt++] = 100;
	sort(e, e+ecnt); sort(s, s+scnt); sort(w, w+wcnt); sort(n, n+ncnt);
	
//	for(int i = 0;i < ecnt; i++) printf("%.2lf ", e[i]); puts("");
//	for(int i = 0;i < scnt; i++) printf("%.2lf ", s[i]); puts("");
//	for(int i = 0;i < wcnt; i++) printf("%.2lf ", w[i]); puts("");
//	for(int i = 0;i < ncnt; i++) printf("%.2lf ", n[i]); puts("");
	
	Point p[200]; int pcnt = 0;
	for(int i = 0;i < ecnt-1; i++) p[pcnt++] = Point(100, (e[i]+e[i+1])/2);
	for(int i = 0;i < scnt-1; i++) p[pcnt++] = Point((s[i]+s[i+1])/2, 0);
	for(int i = 0;i < wcnt-1; i++) p[pcnt++] = Point(0, (w[i]+w[i+1])/2);
	for(int i = 0;i < ncnt-1; i++) p[pcnt++] = Point((n[i]+n[i+1])/2, 100);
	
//	for(int i = 0;i < pcnt; i++) {
//		printf("%.2lf %.2lf\n", p[i].x, p[i].y);
//	}
	
	int ans = 1e9;
	for(int i = 0;i < pcnt; i++) {
		int now = 0;
		Line t = Line(Point(baox, baoy), p[i]);
		for(int j = 0;j < num; j++) {
			if(t.seg_cross_seg(l[j]) == 2) now++;
		}
		ans = min(ans, now);
//		printf("%.2lf %.2lf\n", p[i].x, p[i].y);
//		printf("now = %d\n\n", now);
	}
	
	printf("Number of doors = %d\n", ans+1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值