前置知识点
凸包:
概念
示例图(一)
1 点集Q的凸包(convex hull)是指一个最小凸多边形,满足Q中的点或者在多边形边上或者在其内。右图中由红色线段表示的多边形就是点集Q={p0,p1,...p12}的凸包。
2 一组平面上的点,求一个包含所有点的最小的凸多边形,这就是凸包问题了。这可以形象地想成这样:在地上放置一些不可移动的木桩,用一根绳子把他们尽量紧地圈起来,并且为凸边形,这就是凸包了。
——百度百科
Andrew 算法
是一种求解凸包的一种基本算法
具体过程还不会,等本菜鸡学会了再回来填坑
题意:
有 n 条直线 y=ax+b(a ≠ 0并且总是存在)。 m 次询问,每次询问给出一条直线 y=cx+d,求该直线与已知直线中交点横坐标最大的值是多少,如果没有交点则输出 "No cross"。
学习博客:https://blog.csdn.net/xbb224007/article/details/81158026
讲的超级详细,建议去学习
题解:
有两条直线
y=a*x+b
y=c*x+d
=> x= -(b-d)/(a-c)
这样问题求x的最大值就转化成了求斜率的最小值
这时候就根据凸包求解即可
具体讲解请看上述推荐博客
#include<iostream>
#include<algorithm>
#include<cmath>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<map>
#pragma GCC optimize(2)
#if(__cplusplus == 201103L)
#include <unordered_map>
#include <unordered_set>
#else
#include <tr1/unordered_map>
#include <tr1/unordered_set>
namespace std
{
using std::tr1::unordered_map;
using std::tr1::unordered_set;
}
#endif
#include<tr1/unordered_map>
#include<set>
#include<stack>
#define debug cout<<"*"<<endl;
#define input(x) scanf("%d",&x)
#define output(x) printf("%d\n",x);
#define llinput(x) scanf("%lld",&x)
#define lloutput(x) printf("%lld\n",x);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<string,int> psi;
typedef pair<char,char> pcc;
const int mod=1e9+7;
const int INF=1e9+7;
const int maxn=1e6+7;
const double E=2.718281828;
const double PI=acos(-1);
const double esp=1e-10;
/**
Daily sentence:
The wise man builds no hopes for the future, entertains no regrets for the past.
**/
struct Point{
double x,y;
int id;
Point(){x=y=id=0;}
Point(double _x,double _y)
{
x=_x;
y=_y;
}
}P[maxn],Convexhull[maxn];
double ans[maxn]; //记录每次询问的答案
Point operator + (Point p,Point q)
{
return Point(p.x+q.x,p.y+q.y);
}
Point operator - (Point p,Point q)
{
return Point(p.x-q.x,p.y-q.y);
}
Point operator * (Point p,double d)
{
return Point(p.x*d,p.y*d);
}
Point operator / (Point p,double d)
{
return Point(p.x/d,p.y/d);
}
int dcmp(double x){
return fabs(x)<esp?0:x<0?-1:1;
}
bool operator <(Point p1,Point p2){
return dcmp(p1.x-p2.x)<0||(dcmp(p1.x-p2.x)==0&&dcmp(p1.y-p2.y)<0);
}
double Dot(Point p,Point q) //点乘:(x1,y1)*(x2,y2)=x1*x2+y1*y2
{
return p.x*q.x,p.y*q.y;
}
double Cross(Point p,Point q) //叉乘:(x1,y1)×(x2,y2)=x1*y2-x2*y1
{
return p.x*q.y-p.y*q.x;
}
double Get_slope(Point p) //求斜率
{
return p.y/p.x;
}
double Get_length(Point p) //求长度
{
return sqrt(p.x*p.x+p.y*p.y);
}
//Andrew算法求凸包
void Scan(int n)
{
int top=0;
for(int i=0;i<n;i++)
{
if(P[i].id)
{
if(!top) continue;
int l=0,r=top-1;
while(l<r)
{
int mid=(l+r)>>1;
if(Cross(Convexhull[mid+1]-Convexhull[mid],P[i]-Convexhull[mid])>0)
r=mid;
else
l=mid+1;
}
ans[P[i].id]=min(ans[P[i].id],Get_slope(P[i]-Convexhull[l]));
}
else{
while(top>1&&dcmp(Cross(P[i]-Convexhull[top-2],Convexhull[top-1]-Convexhull[top-2]))<0)
top--;
Convexhull[top++]=P[i];
}
}
}
void Andrew(int n)
{
sort(P,P+n);Scan(n);
reverse(P,P+n);Scan(n);
}
void Init()
{
for(int i=0;i<maxn;i++)
ans[i]=INF;
}
int main()
{
Init();
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>P[i].x>>P[i].y;
}
int m;
cin>>m;
for(int i=n;i<n+m;i++)
{
P[i].id=i-n+1;
cin>>P[i].x>>P[i].y;
}
Andrew(n+m);
for(int i=1;i<=m;i++)
{
if(dcmp(ans[i])>0) printf("No cross\n");
else printf("%.12lf\n",-ans[i]);
}
return 0;
}
来源:https://blog.csdn.net/weixin_43916296/article/details/100807526