线段的性质
(1)叉积
p1×p2=x1*y2-x2*y1=-p2×p1
(2)确定连续线段是向左转还是向右转
p0p1、p1p2
(p1-p0)×(p2-p0)>0,向左转;
(p1-p0)×(p2-p0)<0,向右转;
(p1-p0)×(p2-p0)=0,p0、p1、p2三点共线。
(3)判断两条线段是否相交
struct point
{
int x,y;
};
int direction(point pi,point pj,point pk)
{
//(pk-pi)×(pj-pi)
return (pk.x-pi.x)*(pj.y-pi.y)-(pj.x-pi.x)*(pk.y-pi.y);
}
bool onSegment(point pi,point pj,point pk)
{
if(min(pi.x,pj.x)<=pk.x&&pk.x<=max(pi.x,pj.x)&&min(pi.y,pj.y)<=pk.y&&pk.y<=max(pi.y,pj.y))return true;
else return false;
}
bool segmentsIntersect(point p1,point p2,point p3,point p4)
{
int d1=direction(p3,p4,p1);
int d2=direction(p3,p4,p2);
int d3=direction(p1,p2,p3);
int d4=direction(p1,p2,p4);
if((d1>0&&d2<0)||(d1<0&&d2>0)||(d3>0&&d4<0)||(d3<0&&d4>0))return true;
else if(d1==0&&onSegment(p3,p4,p1))return true;
else if(d2==0&&onSegment(p3,p4,p2))return true;
else if(d3==0&&onSegment(p1,p2,p3))return true;
else if(d4==0&&onSegment(p1,p2,p4))return true;
else return false;
}
确定任意一对线段是否相交
寻找凸包
Graham扫描法,时间复杂度为O(nlogn)
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct point
{
int x,y;
}p;
int crossProduct(point a,point b,point c)
{
return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
//距离的平方
int dist(point a,point b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp(point b,point c)
{
if(crossProduct(p,b,c)>0||(crossProduct(p,b,c)==0&&dist(p,b)<dist(p,c)))return true;
return false;
}
vector<point> GrahamScan(vector<point> Q)
{
int bottom=0;
for(int i=1;i<Q.size();++i)
{
if((Q[i].y<Q[bottom].y)||(Q[i].y==Q[bottom].y&&Q[i].x<Q[bottom].x))bottom=i;
}
p=Q[bottom];
Q[bottom]=Q[0];
Q[0]=p;
sort(Q.begin()+1,Q.end(),cmp);
for(vector<point>::iterator i=Q.begin()+1;i+1!=Q.end();)
{
if(crossProduct(p,*i,*(i+1))==0)i=Q.erase(i);
else ++i;
}
vector<point> S;
if(Q.size()<3)return S;
S.push_back(Q[0]);
S.push_back(Q[1]);
S.push_back(Q[2]);
for(int i=3;i<Q.size();++i)
{
while(crossProduct(*(S.rbegin()+1),*S.rbegin(),Q[i])<=0)S.pop_back();
S.push_back(Q[i]);
}
return S;
}
//输入
//9
//1 1
//1 2
//1 3
//2 1
//2 2
//2 3
//3 1
//3 2
//3 3
//输出
//(1,1) (3,1) (3,3) (1,3)
int main()
{
int n;
cin>>n;
vector<point> Q(n);
for(int i=0;i<n;++i)cin>>Q[i].x>>Q[i].y;
vector<point> S=GrahamScan(Q);
for(int i=0;i<S.size();++i)cout<<'('<<S[i].x<<','<<S[i].y<<')'<<' ';
return 0;
}
寻找最远点对
凸包+旋转卡壳,时间复杂度为O(nlogn)+O(n)=O(nlogn)
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct point
{
int x,y;
}p;
int crossProduct(point a,point b,point c)
{
return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}
//距离的平方
int dist(point a,point b)
{
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool cmp(point b,point c)
{
if(crossProduct(p,b,c)>0||(crossProduct(p,b,c)==0&&dist(p,b)<dist(p,c)))return true;
return false;
}
vector<point> GrahamScan(vector<point> Q)
{
int bottom=0;
for(int i=1;i<Q.size();++i)
{
if((Q[i].y<Q[bottom].y)||(Q[i].y==Q[bottom].y&&Q[i].x<Q[bottom].x))bottom=i;
}
p=Q[bottom];
Q[bottom]=Q[0];
Q[0]=p;
sort(Q.begin()+1,Q.end(),cmp);
for(vector<point>::iterator i=Q.begin()+1;i+1!=Q.end();)
{
if(crossProduct(p,*i,*(i+1))==0)i=Q.erase(i);
else ++i;
}
vector<point> S;
if(Q.size()<3)return S;
S.push_back(Q[0]);
S.push_back(Q[1]);
S.push_back(Q[2]);
for(int i=3;i<Q.size();++i)
{
while(crossProduct(*(S.rbegin()+1),*S.rbegin(),Q[i])<=0)S.pop_back();
S.push_back(Q[i]);
}
return S;
}
//旋转卡壳算法
int rotatingCalipers(vector<point> S)
{
int n=S.size(),j=1,maxDist=0;
S.push_back(S[0]);
for(int i=0;i<n;++i)
{
while(crossProduct(S[i],S[i+1],S[j+1])>crossProduct(S[i],S[i+1],S[j]))j=(j+1)%n;
maxDist=max(maxDist,max(dist(S[i],S[j]),dist(S[i+1],S[j+1])));
}
return maxDist;
}
//输入
//9
//1 1
//1 2
//1 3
//2 1
//2 2
//2 3
//3 1
//3 2
//3 3
//输出
//8
int main()
{
int n;
cin>>n;
vector<point> Q(n);
for(int i=0;i<n;++i)cin>>Q[i].x>>Q[i].y;
vector<point> S=GrahamScan(Q);
cout<<rotatingCalipers(S)<<endl;
return 0;
}
寻找最近点对
分治,时间复杂度为O(nlogn)
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N=100;
struct point
{
int x,y;
}p[N];
double dist(point a,point b)
{
return sqrt(double((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)));
}
bool cmpx(point a,point b)
{
return a.x<b.x;
}
bool cmpy(point a,point b)
{
return a.y<b.y;
}
double minDist(int l,int r)
{
if(l+1==r)return dist(p[l],p[r]);
if(l+2==r)return min(min(dist(p[l],p[l+1]),dist(p[l+1],p[r])),dist(p[l],p[r]));
int mid=l+(r-l)/2;
double delta=min(minDist(l,mid),minDist(mid+1,r));
vector<point> q;
for(int i=l;i<=r;++i)
{
if(abs(p[i].x-p[mid].x)<=delta)q.push_back(p[i]);
}
sort(q.begin(),q.end(),cmpy);
for(int i=0;i<q.size();++i)
{
for(int j=1;j<=7;++j)
{
if(i+j<q.size())
{
if(dist(p[i],p[i+j])<delta)delta=dist(p[i],p[i+j]);
else break;
}
}
}
return delta;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;++i)cin>>p[i].x>>p[i].y;
sort(p,p+n,cmpx);
cout<<minDist(0,n-1)<<endl;
return 0;
}