NYOJ83——迷宫寻宝(二)

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=83

题目分析:
好吧,我承认这个题折腾了我接近两个小时~~可怜可怜
其实这道题就是任选一个四周墙壁上的点,然后与目标点连成一个线段,然后求该线段与所给的所有线段的交点数。取最少的交点数。
不过这道题很坑爹啊,要求输入的点的坐标是整数,结构后来目标点的坐标却不一定是整数,为什么不全部要求是浮点数呢?只要有一个是整数,定义的结构体就要是整数啊~~而且题目叙述中给的输入顺序是x1,x2,y1,y2,我还纳闷为什么这个顺序跟常规思维有点不一样,结果测试一下,错了。然后结合它给的图和数据一看,我知道被坑了,其实顺序应该是x1,y1,x2,y2的,偶只好赶紧把顺序改过来,这就对了。

参考代码:

#include<stdio.h>
#include<math.h>

typedef struct  
{
	double x;
	double y;
}POINT;

typedef struct  
{
	POINT p1;
	POINT p2;
}LINE;

inline double CrossProduct(POINT *p1, POINT *p2, POINT *p3)
{
	return (p2->x - p1->x) * (p2->y - p3->y) - (p2->x - p3->x) * (p2->y - p1->y);
}

inline double min(const double a, const double b)
{
	return a < b ? a : b;
}

inline double max(const double a, const double b)
{
	return a > b ? a : b;
}

inline bool InSegment(POINT *p, LINE *l)
{//判断点是否在线段中
	if(p->x >= min(l->p1.x, l->p2.x) && p->x <= max(l->p1.x, l->p2.x)
		&& p->y >= min(l->p1.y, l->p2.y) && p->y <= max(l->p1.y, l->p2.y))
		return true;
	else
		return false;

}

bool SegmentIntersect(LINE *l1, LINE *l2)
{//判断两个线段是否相交,第一个是判断是否相交,后面四个if是判断其中一个线段是否包含了另一个线段的端点
	double d1 = CrossProduct(&l1->p1, &l1->p2, &l2->p1);
	double d2 = CrossProduct(&l1->p1, &l1->p2, &l2->p2);
	double d3 = CrossProduct(&l2->p1, &l2->p2, &l1->p1);
	double d4 = CrossProduct(&l2->p1, &l2->p2, &l1->p2);
	if( ((d1 < 0 && d2 > 0) || (d1 > 0 && d2 < 0)) && 
		((d3 < 0 && d4 > 0) || (d3 > 0 && d4 < 0)))
		return true;
	else if(fabs(d1) < 0.0000001 && InSegment(&l2->p1, l1))
		return true;
	else if(fabs(d2) < 0.0000001 && InSegment(&l2->p2, l1))
		return true;
	else if(fabs(d3) < 0.0000001 && InSegment(&l1->p1, l2))
		return true;
	else if(fabs(d4) < 0.0000001 && InSegment(&l1->p2, l2))
		return true;
	else
		return false;
}

int GetIntersect(LINE *l, int n, POINT *p)
{//求交点数
	int i,j;
	int ans,count;
	ans = 35;
	LINE line;
	line.p2 = *p;
	//左
	line.p1.x = 0.0;
	for(i = 1; i < 100; ++i)
	{
		line.p1.y = i;
		count = 0;
		for(j = 0; j < n; ++j)
		{
			if((fabs(l[j].p1.x) < 0.0000001 && l[j].p1.y == i) ||
				(fabs(l[j].p2.x) < 0.0000001 && l[j].p2.y == i))
				continue;
			if(SegmentIntersect(&line,&l[j]))
				++count;
		}
		ans = min(ans, count);
	}
	//右
	line.p1.x = 100;
	for(i = 1; i < 100; ++i)
	{
		line.p1.y = i;
		count = 0;
		for(j = 0; j < n; ++j)
		{
			if((l[j].p1.x == 100.0 && l[j].p1.y == i) ||
				(l[j].p2.x == 100.0 && l[j].p2.y == i))
				continue;
			if(SegmentIntersect(&line,&l[j]))
				++count;
		}
		ans = min(ans, count);
	}
	//下
	line.p1.y = 0.0;
	for(i = 1; i < 100; ++i)
	{
		line.p1.x = i;
		count = 0;
		for(j = 0; j < n; ++j)
		{
			if((fabs(l[j].p1.y) < 0.0000001 && l[j].p1.x == i) ||
				(fabs(l[j].p2.y) < 0.0000001 && l[j].p2.x == i))
				continue;
			if(SegmentIntersect(&line,&l[j]))
				++count;
		}
		ans = min(ans, count);
	}
	//左
	line.p1.y = 100;
	for(i = 1; i < 100; ++i)
	{
		line.p1.x = i;
		count = 0;
		for(j = 0; j < n; ++j)
		{
			if((l[j].p1.y == 100.0 && l[j].p1.x == i) ||
				(l[j].p2.y == 100.0 && l[j].p2.x == i))
				continue;
			if(SegmentIntersect(&line,&l[j]))
				++count;
		}
		ans = min(ans, count);
	}
	return ans;
}

int main()
{
	int n,t;
	int i,ans;
	LINE line[35];
	POINT p;
	scanf("%d",&t);
	//左
	line[0].p1.x = 0;
	line[0].p1.y = 0;
	line[0].p2.x = 0;
	line[0].p2.y = 100;
	//右
	line[1].p1.x = 100;
	line[1].p1.y = 0;
	line[1].p2.x = 100;
	line[1].p2.y = 100;
	//下
	line[2].p1.x = 0;
	line[2].p1.y = 0;
	line[2].p2.x = 100;
	line[2].p2.y = 0;
	//上
	line[3].p1.x = 0;
	line[3].p1.y = 100;
	line[3].p2.x = 100;
	line[3].p2.y = 100;

	while(t--)
	{
		scanf("%d",&n);
		n += 4;
		for(i = 4; i < n; ++i)
			scanf("%lf %lf %lf %lf", &line[i].p1.x, &line[i].p1.y, &line[i].p2.x,  &line[i].p2.y);
		scanf("%lf %lf", &p.x, &p.y);
		ans = GetIntersect(line, n, &p);
		printf("%d\n",ans);
	}
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值