POJ4048

一道计算几何题目,给定n个墙和一个人的坐标,弓箭可以射穿墙,求一次射击最多能射穿多少个墙。通过以人的坐标为起点,墙的端点为终点,判断线段交点来解决,通过枚举所有墙的端点更新最大射穿数。

题目链接:POJ4048


题意:

n个墙,给定一个人有一把弓箭,可以选择任意的方位射击,弓箭可以射穿墙,问一次最多能射穿多少个墙。

T,T组数据。

每组数据先输入一个n,代表n个墙。

然后n行,每列给出墙的两个端点坐标。

然后是人的坐标。

输出最多射穿的墙的个数。


分析:

以人的坐标设置为线段的起点,以连接到某个线段的端点的无线延伸作为终点,求该线段与n个墙是否有交点,有的话就累加。

枚举全部墙的两个端点。不断更新最大值。


代码实现:


#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <map>
#include <iostream>
#include <string>
#include <utility>
#include <vector>
using namespace std;
int n, M, k, tn, tcase = 0;
const int MAX=1500+10;
const double eps=1e-9;

struct Point
{
	double x,y;
	Point(){}
	Point(double xx, double yy) : x(xx), y(yy) {}
	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.y - y * b.x;
	}
	double operator *(const Point &b) const
	{
		return x * b.x + y * b.y;
	}
}p1[MAX],p2[MAX];



int sgn(double x)
{
	if(fabs(x)<eps)
		return 0;
	else if(x<0)
		return -1;
	else 
		return 1;
}


int seg(Point a,Point b,Point c,Point d)
{
	int d1=sgn((a-b)^(d-b));
	int d2=sgn((a-b)^(c-b));
	int d3=sgn((c-d)^(b-d));
	int d4=sgn((c-d)^(a-d));

	if((d1^d2)==-2&&(d3^d4)==-2)
		return 2;
	return 
		(d1==0&&sgn((d-b)*(d-a))<=0)||
		(d2==0&&sgn((c-b)*(c-a))<=0)||
		(d3==0&&sgn((b-d)*(b-c))<=0)||
		(d4==0&&sgn((a-d)*(a-c))<=0);
}

int main()
{
	// freopen("in.txt", "r", stdin);

	int T,n;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		for(int i=0;i<n;i++)
		{
			scanf("%lf %lf %lf %lf",&p1[i].x,&p1[i].y,&p2[i].x,&p2[i].y);
		}
		Point s;
		scanf("%lf %lf",&s.x,&s.y);


	int Max=0,cnt1,cnt2;
	for(int i=0;i<n;i++)
	{
		cnt1=cnt2=0;
		//t1 t2 分别是人的坐标到某墙两个端点的无线延伸
		Point t1,t2;
		t1.x=(p1[i]-s).x*10000;
		t1.y=(p1[i]-s).y*10000;
		t1=t1+s;

		t2.x=(p2[i]-s).x*10000;
		t2.y=(p2[i]-s).y*10000;
		t2=t2+s;

		for(int j=0;j<n;j++)
		{
			// 判断线段间是否相交
			// 在端点上相交返回 1 在其他地方相交返回 2 
			// 否则返回 0
			if(seg(s,t1,p1[j],p2[j])!=0)
				cnt1++;
			if(seg(s,t2,p1[j],p2[j])!=0)
				cnt2++; 
		}
		Max=max(cnt1,Max);
		Max=max(cnt2,Max);
	}
	printf("%d\n",Max);
	}
		
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值