数学集:点与线

模版前导:

struct Point{
	double x,y;
}p[N];
//点积代码
//a*b=0,两向量垂直
//a*b==|a||b|,两向量平行
double dot(Point a,Point b){
  return a.x*b.x+a.y*b.y;
}
//求模长
double len(Point a){
  return sqrt(a.x*a.x+a.y+a.y);
}
//a*b/|a||b|,计算夹角
double angle(Point a,Point b){
  return acos(dota,b)/len(a)/len(b));
}
//>0,点在线的左侧
//=0,点在线上
//<0,点在线的右侧
double cross(Point a,Point b,Point c){
	return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}

题目一:

原题链接:Transmitters

题意:

题目存在多组输入,先给你三个值x,y,r,分别是圆心的坐标及半径,接下来有n个点,每次给你点的坐标,求以圆心为中心的半圆最多能覆盖多少个点。

解题思路:

拿到本题首先考虑满足因素,先判断有多少个点在圆内,再将处于圆内的点提取出来,依次遍历每个点与圆心作为线时(点的数据量为1000,不会超时),有多少点能被覆盖,这里就需要用到叉积的性质来判断点与线的位置。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<cstdlib>
#include<algorithm>
#include<string>
#include<bitset>
#include<map>
#include<queue>
#include<stack>

#define FAST_READ                        \
    ios::sync_with_stdio(0), cin.tie(0); \
cout.tie(0);
using namespace std;

const int N=1e6+10;

int t;
double r;
//点的结构体
struct Point{
	double x,y;
}o,p[N],a;
//两点间距离公式
double dis(Point a,Point b){
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
//计算叉积
double cross(Point a,Point b,Point c){
	return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}

int main()
{
	FAST_READ; 
	while(cin >>o.x>>o.y>>r)
	{
		if (r<0)return 0;
		cin >>t;
		int top=0,maxn=0;
		while(t--)
		{
			cin >>a.x>>a.y;
		  //在圆内就放入
			if (dis(a,o)<=r)p[top++]=a;
		}
		for (int i=0;i<top;i++)
		{
			int cnt=0;
			for (int j=0;j<top;j++)
			{
			  //当点在线的左侧或在线上时,记录该点
				if (cross(o,p[i],p[j])>=0)cnt++;
			}
			maxn=max(maxn,cnt);
		}
		cout <<maxn<<"\n";
	} 
	return 0;
}

题目二:

原题链接:TOYS

题意:

题目存在多组输入,先给你六个值,n,m,x1,y1,x2,y2(题目中因为x1,y1导致编程错误,所以在实际题目中更改了变量名),x1,y1为矩阵的左上坐标,x2,y2为矩阵的右下坐标,接下来n行,每次给你分割区间的上下两个坐标,即每次给你的都是x轴坐标,y轴坐标都是固定的,接下来m行,每次给你两个坐标表示玩具的个数,矩阵被线段分割的每个区间中有多少玩具。

解题思路:

既然要判断每个区间有多少玩具,这里用叉积的点线判断后,就变成单纯的二分问题了,剩下的难点估计就是点的记录,太绕了。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<cstdlib>
#include<algorithm>
#include<string>
#include<bitset>
#include<map>
#include<queue>
#include<stack>

#define FAST_READ                        \
    ios::sync_with_stdio(0), cin.tie(0); \
cout.tie(0);
using namespace std;

const int N=1e6+10;

int n,m,u,l;
double lx,rx,ly,ry;
int ans[N];
struct Point{
	double x,y;
}a[N],b[N],o;
//叉积公式,判断点在线的那一端 
double cross(Point a,Point b,Point c){
	return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
//数据量点有5000,线有5000,必须要有优化
//二分查找 
int find(Point o){
	int l=-1,r=n+1;
	while(l+1<r)
	{
		int mid=l+(r-l)/2;
		//当叉积小于等于0时点在线的右侧或在线上 
		if (cross(b[mid],a[mid],o)<=0)l=mid;
		else r=mid;
	}
	return l;
}

int main()
{
	FAST_READ; 
	bool flag=0;
	while(cin >>n)
	{
		if (n==0)return 0;
		cin >>m>>lx>>ly>>rx>>ry;
		//左边区间顶点 
		a[0].x=b[0].x=lx;
		a[0].y=ly;
		b[0].y=ry;
		for (int i=1;i<=n;i++)
		{
			cin >>u>>l;
			//记录每条线 
			a[i].x=u;
			a[i].y=ly;
			b[i].x=l;
			b[i].y=ry;
		}
		//初始化记录的ans 
		for (int i=0;i<=n;i++)ans[i]=0;
		while(m--)
		{
			cin >>o.x>>o.y;
			//在那个区间就加在哪里 
			ans[find(o)]++;
		}
		if (!flag)flag=1;
		else cout <<"\n";
		for (int i=0;i<=n;i++)cout <<i<<": "<<ans[i]<<"\n";
	}
	return 0;
}

全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务