【计算几何-技巧】射击游戏

Description
js在ak了一套cf后,打开了一款新出的射击游戏。

这个射击游戏在一个二维平面进行,js控制的人物处于坐标原点(0,0)。平面上共有n只怪物,每个怪物所在的坐标为(x[i], y[i])。js进行一次射击会把x轴和y轴上(包含坐标原点)的怪物一次性消灭。

而高贵的js是这个游戏的VIP玩家,他拥有两项特权操作:
1、让平面内的所有怪物向任意一个相同的方向移动相同的距离d。
2、让平面内的所有怪物以js为中心旋转相同的角度θ。

js在进行射击前,可以无限次的使用这两项特权操作。js想知道在他射击的时候最多可以同时消灭多少只怪物,请你帮帮伟大的js吧。

Input
输入包括三行。

第一行中有一个正整数n(1 <= n <= 100),表示平面内的怪物数量。

第二行包括n个由空格分隔的整数x[i](-1,000,000 <= x[i] <= 1,000,000),表示每只怪物的横坐标。

第二行包括n个由空格分隔的整数y[i](-1,000,000 <= y[i] <= 1,000,000),表示每只怪物的纵坐标。

Output
输出js一次性最多能消灭的怪物数。

Sample Input
5
0 -1 1 1 -1
0 -1 -1 1 1
Sample Output
5

枚举两个点,连成一条线。每次检查在线上有多少点,不在线上的点往线上作投影,当线上的点+某个投影的坐标的所有点>答案的时候,更新答案。

是否三点一线用向量是否平行,投影也用向量坐标运算。

技巧:投影用map来存储,遍历的时候用map的迭代器进行遍历。重载运算符实现坐标相减得到向量的功能。

答案初始化为1;因为如果没有能构成线点,那么将不运算

#include<bits/stdc++.h>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
struct point{
	ll x, y;
	point(){}
	point(ll x,ll y):x(x),y(y){}
	point operator -(point tp)
	{
		return point(x-tp.x,y-tp.y);
	}
}p[110];
ll dot(point a,point b)
{
	return a.x*b.x+a.y*b.y;
}
ll cross(point a,point b)
{
	return a.x*b.y-b.x*a.y;
}
ll on(point a,point b,point c)
{
	return cross(c-a,c-b)==0;
}
int main()
{
	ll n;
	ll ans=1;
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++)
	{
		scanf("%lld",&p[i].x);
	}
	for(ll i=1;i<=n;i++)
	{
		scanf("%lld",&p[i].y);
	}
	for(ll i=1;i<=n;i++)
	{
		for(ll j=i+1;j<=n;j++)
		{
			ll cnt=0;
			map<ll,ll> cnt2;
			point v=p[j]-p[i];
			for(ll k=1;k<=n;k++)
			{
				if(on(p[i],p[j],p[k])) cnt++;
				else cnt2[dot(v,p[k])]++;
			}
			ans=max(ans,cnt);
			for(map<ll,ll>::iterator it=cnt2.begin();it!=cnt2.end();it++ )
			{
				ans=max(ans,cnt + it->second );
			}
		}
	}
	printf("%lld",ans);
} 

 

发表评论

邮箱地址不会被公开。 必填项已用*标注