2021.11.22 凸包
虽然我菜吧,但也要菜得有水平!
1. 定义
1.1
简称用最短的线框住所有点。
1.2 叉乘cross
设点 \(O(0,0)\) , \(A(x1,y1)\) , \(B(x2,y2)\), \(OA=l1=\sqrt{x_1^2+y_1^2}\) , \(OB=l2=\sqrt{x_1^2+y_2^2}\) , \(\theta = <\overrightarrow{OA},\overrightarrow{OB}>\) , \(\alpha= <\overrightarrow{OX},\overrightarrow{OB}>\) , \(\beta= <\overrightarrow{OX},\overrightarrow{OA}>\)。
1.3点乘dot
设点 \(O(0,0)\) , \(A(x1,y1)\) , \(B(x2,y2)\), \(OA=l1=\sqrt{x_1^2+y_1^2}\) , \(OB=l2=\sqrt{x_1^2+y_2^2}\) , \(\theta = <\overrightarrow{OA},\overrightarrow{OB}>\) , \(\alpha= <\overrightarrow{OX},\overrightarrow{OB}>\) , \(\beta= <\overrightarrow{OX},\overrightarrow{OA}>\)。
1.4
两点相减:从被减的点到减它的点有一条向量
2. Andrew算法
如果只是从起点逆时针左转,可以得到一个下凸壳,然后从终点开始顺时针右转,可以得到一个上凸壳,吧唧,成了一个凸壳~
https://www.luogu.com.cn/problem/P2742
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,top,vis[N],stacki[N],fin[N];
struct node{
double x,y;
bool operator <(const node &b)const{
return x==b.x?y<b.y:x<b.x;
}
}a[N];
inline double chacheng(int a1,int a2,int b1,int b2){
return (a[a2].x-a[a1].x)*(a[b2].y-a[b1].y)-(a[a2].y-a[a1].y)*(a[b2].x-a[b1].x);
}
inline double dis(double x,double y,double u,double v){
return (double)sqrt((double)(x-u)*(double)(x-u)+(double)(y-v)*(double)(y-v));
}
inline void tubao(){
sort(a+1,a+n+1);
//for(int i=1;i<=n;i++)cout<<a[i].x<<" "<<a[i].y<<endl;//
stacki[++top]=1;
stacki[++top]=2;
for(int i=3;i<=n;i++){
while(top>=2&&chacheng(stacki[top-1],stacki[top],stacki[top],i)<0)--top;
vis[i]=1;
stacki[++top]=i;
}
//for(int i=1;i<=top;i++)cout<<stacki[i]<<" ";cout<<endl;
int tmp=top;
//stacki[++top]=n;
stacki[++top]=n-1;
for(int i=n-2;i>=1;i--)
/*if(!vis[i])*/{
while(top>tmp&&chacheng(stacki[top-1],stacki[top],stacki[top],i)<0)
vis[stacki[top]]=0,--top;
vis[i]=1;
stacki[++top]=i;
}
//for(int i=1;i<=top;i++)cout<<stacki[i]<<" ";cout<<endl;
double ans=0;
for(int i=1;i<top;i++){
int x=stacki[i],y=stacki[i+1];
ans+=dis(a[x].x,a[x].y,a[y].x,a[y].y);
}
printf("%.2lf",ans);
}
int main(){
//ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].y;
tubao();
return 0;
}
https://www.luogu.com.cn/problem/UVA11626
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
int t,n,top,stacki[N];
struct node{
int x,y;
bool operator <(const node &b)const{
return x==b.x?y<b.y:x<b.x;
}
}a[N];
inline int chacheng(int x,int y,int z){
return (a[y].x-a[x].x)*(a[z].y-a[y].y)-(a[y].y-a[x].y)*(a[z].x-a[y].x);
}
inline void tubao(){
sort(a+1,a+n+1);
/*if(n==3){
cout<<n<<endl;
for(int i=1;i<=n;i++)cout<<a[i].x<<" "<<a[i].y<<endl;
return ;
}*/
stacki[++top]=1;stacki[++top]=2;
for(int i=3;i<=n;i++){
while(top>=2&&chacheng(stacki[top-1],stacki[top],i)<0)--top;
stacki[++top]=i;
}
int tmp=top;
stacki[++top]=n-1;
for(int i=n-2;i>=1;i--){
while(top>tmp&&chacheng(stacki[top-1],stacki[top],i)<0)--top;
stacki[++top]=i;
}
//for(int i=1;i<=top;i++)cout<<stacki[i]<<" ";cout<<endl;
cout<<top-1<<endl;
for(int i=1;i<top;i++)cout<<a[stacki[i]].x<<" "<<a[stacki[i]].y<<endl;
}
signed main(){
//freopen("uva116626.out","w",stdout);
ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>t;
while(t--){
cin>>n;
top=0;
memset(stacki,0,sizeof(stacki));
//memset(&a,0,sizeof(a));
int ni=n;n=0;
for(int i=1;i<=ni;i++){
int x,y;
char ch;
cin>>x>>y>>ch;
//if(ch=='N')continue;
++n;
a[n].x=x;a[n].y=y;
}
tubao();
}
return 0;
}
https://www.luogu.com.cn/problem/P2521
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1e5+10;
int n,m,X,Y,top,vis[N];
double ans,river;
struct node{
double x,y;
int id;
bool operator <(const node &b)const{
return x==b.x?y<b.y:x<b.x;
}
}a[N],stacki[N];
inline node operator +(node x,node y){
return (node){x.x+y.x,x.y+y.y,0};
}
inline node operator -(node x,node y){
return (node){x.x-y.x,x.y-y.y,0};
}
inline double cross(node x,node y){
return x.x*y.y-x.y*y.x;
}
inline double dis(node x){
return (double)sqrt(x.x*x.x+x.y*x.y);
}
inline void Andrew(){
top=0;
for(int i=1;i<=n;i++)if(vis[i]!=2)vis[i]=0;
for(int i=1;i<=n;i++)if(vis[a[i].id]!=2){
if(top<2)stacki[++top]=a[i],vis[stacki[top].id]=1;
else{
while(top>=2&&cross(stacki[top]-stacki[top-1],a[i]-stacki[top])<=0)
vis[stacki[top].id]=0,--top;
stacki[++top]=a[i];
vis[stacki[top].id]=1;
}
}
int tmp=top;
for(int i=n-1;i>=1;i--)if(vis[a[i].id]!=2){
while(top>tmp&&cross(stacki[top]-stacki[top-1],a[i]-stacki[top])<=0)
vis[stacki[top].id]=0,--top;
stacki[++top]=a[i];
vis[stacki[top].id]=1;
}
//cout<<"array stacki[i]"<<endl;
//for(int i=1;i<=top;i++)cout<<stacki[i].id<<" "<<stacki[i].x<<" "<<stacki[i].y<<endl;
ans=0.0;
for(int i=1;i<top;i++)ans+=dis(stacki[i+1]-stacki[i]);
}
int main(){
cin>>n;river=n;
a[1].x=a[1].y=0;a[1].id=1;
a[2].x=n;a[2].y=0;a[2].id=2;
cin>>X>>Y;
a[3].x=X;a[3].y=Y;a[3].id=3;
cin>>n;
for(int i=4;i<=n+3;i++)cin>>a[i].x>>a[i].y,a[i].id=i;
n+=3;
sort(a+1,a+n+1);
cin>>m;
Andrew();
int flag=0;
for(int i=1;i<=m;i++){
int op,x;
cin>>op;
if(op==2){
if(flag==1)Andrew(),flag=0;
printf("%.2lf\n",ans-river);
}else if(op==1){
cin>>x;x+=3;
if(vis[x]==1)flag=1;
vis[x]=2;
}
}
return 0;
}
https://www.luogu.com.cn/problem/P3829
PS:本题应用转角公式,以及pi为 acos(-1.0) 。
//这道题和UVA1303不能说很像,只能说一模一样
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=4e4+10;
int n,top;
double A,B,R;
struct node{
double x,y;
bool operator <(const node &b)const{
return x==b.x?y<b.y:x<b.x;
}
node operator +(const node &b)const{
return (node){x+b.x,y+b.y};
}
node operator -(const node &b)const{
return (node){x-b.x,y-b.y};
}
node operator *(const double &b)const{
return (node){x*b,y*b};
}
node operator /(const double &b)const{
return (node){x/b,y/b};
}
}a[N],stacki[N];
inline double cross(node x,node y){
return x.x*y.y-x.y*y.x;
}
inline double dot(node x,node y){
return x.x+y.x+x.y*y.y;
}
inline double dis(node x,node y){
return (double)sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
}
inline node rotate(node x,double theta){
double sini=sin(theta),cosi=cos(theta);
return (node){x.x*cosi-x.y*sini,x.y*cosi+x.x*sini};
}
inline void Andrew(){
top=0;n*=4;
sort(a+1,a+n+1);
stacki[++top]=a[1];stacki[++top]=a[2];
for(int i=3;i<=n;i++){
while(top>=2&&cross(stacki[top]-stacki[top-1],a[i]-stacki[top])<=0)--top;
stacki[++top]=a[i];
}
int tmp=top;
stacki[++top]=a[n-1];
for(int i=n-2;i>=1;i--){
while(top>tmp&&cross(stacki[top]-stacki[top-1],a[i]-stacki[top])<=0)--top;
stacki[++top]=a[i];
}
double ans=(double)R*acos(-1.0)*2;
for(int i=1;i<top;i++)ans+=dis(stacki[i],stacki[i+1]);
printf("%.2lf",ans);
}
int main(){
cin>>n;
cin>>B>>A>>R;
A/=2.0;B/=2.0;
for(int i=1;i<=n;i++){
double x,y,theta;
cin>>x>>y>>theta;
node jz=(node){x,y};
a[(i-1)*4+1]=rotate((node){A-R,B-R},theta)+jz;
a[(i-1)*4+2]=rotate((node){-A+R,-B+R},theta)+jz;
a[(i-1)*4+3]=rotate((node){A-R,-B+R},theta)+jz;
a[(i-1)*4+4]=rotate((node){-A+R,B-R},theta)+jz;
}
Andrew();
return 0;
}
3. Graham算法
http://poj.org/problem?id=1113
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
int n,l,stacki[N],top;
struct node{
double x,y;
}a[N];
inline int chacheng(node x,node y,node z){
return (y.x-x.x)*(z.y-y.y)-(y.y-x.y)*(z.x-y.x);
}
inline double dis(node x,node y){
return (double)sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
}
inline bool cmp(node x,node y){
int ans=chacheng(a[0],x,y);
if(ans>0)return true;
if(ans==0&&dis(a[0],x)<dis(a[0],y))return true;
return false;
}
inline void Graham(){
int aim=0;
for(int i=1;i<n;i++)if(a[aim].x<a[i].x||(a[aim].x==a[i].x&&a[aim].y>a[i].y))aim=i;
swap(a[aim],a[0]);
sort(a+1,a+n,cmp);
top=-1;
stacki[++top]=0;stacki[++top]=1;stacki[++top]=2;
for(int i=3;i<n;i++){
while(top>=2&&chacheng(a[stacki[top-1]],a[stacki[top]],a[i])<0)--top;
stacki[++top]=i;
}
stacki[++top]=stacki[0];
//for(int i=0;i<=top;i++)cout<<stacki[i]<<" ";cout<<endl;
double ans=acos(-1.0)*l*2;
for(int i=0;i<top;i++)ans+=dis(a[stacki[i]],a[stacki[i+1]]);
printf("%.0f",ans);
}
int main(){
while(scanf("%d %d",&n,&l)!=EOF){
for(int i=0;i<n;i++)cin>>a[i].x>>a[i].y;
Graham();
}
return 0;
}
4.旋转卡壳
此标题共有 \(2^4\) 种读法,我选择……你猜?
https://blog.csdn.net/qq_30974369/article/details/76408050
模板:
https://www.luogu.com.cn/problem/P1452
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define int long long
const int N=5e4+10;
int n,stacki[N],top,vis[N];
struct node{
int x,y;
bool operator <(const node &b)const{
return x==b.x?y<b.y:x<b.x;
}
}a[N];
inline int chacheng(int x,int y,int z){
return (a[y].x-a[x].x)*(a[z].y-a[y].y)-(a[y].y-a[x].y)*(a[z].x-a[y].x);
}
inline int dis(int x,int y){
return (a[x].x-a[y].x)*(a[x].x-a[y].x)+(a[y].y-a[x].y)*(a[y].y-a[x].y);
}
inline void Andrew(){
sort(a+1,a+n+1);
stacki[++top]=1;stacki[++top]=2;
for(int i=3;i<=n;i++){
while(top>=2&&chacheng(stacki[top-1],stacki[top],i)<=0)--top;
stacki[++top]=i;
}
int tmp=top;
stacki[++top]=n-1;
for(int i=n-2;i>=1;i--){
while(top>tmp&&chacheng(stacki[top-1],stacki[top],i)<=0)--top;
stacki[++top]=i;
}
}
inline int maxn(){
int ans=0;
int aim=2;
for(int i=1;i<top;i++){
ans=max(ans,dis(stacki[i],stacki[i+1]));
while(chacheng(stacki[i],stacki[i+1],stacki[aim])<chacheng(stacki[i],stacki[i+1],stacki[aim+1]))
aim=(aim+1)%top;
//面积越大距离越远
ans=max(ans,max(dis(stacki[i],stacki[aim]),dis(stacki[i+1],stacki[aim])));
}
return ans;
}
signed main(){
ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].y;
Andrew();
cout<<maxn();
return 0;
}
4.1 最小矩形覆盖
https://www.luogu.com.cn/problem/P3187
只需要输出一个换行就行,呵呵了,破样例!!
// https://www.luogu.com.cn/blog/Huah/solution-p3187
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=5e4+10;
int n,stacki[N],top;
struct node{
double x,y;
bool operator <(const node &b)const{
return x==b.x?y<b.y:x<b.x;
}
}a[N],fin[5];
node operator +(node a,node b){
return (node){a.x+b.x,a.y+b.y};
}
node operator -(node a,node b){
return (node){a.x-b.x,a.y-b.y};
}
node operator *(node a,double b){
return (node){a.x*b,a.y*b};
}
node operator /(node a,double b){
return (node){a.x/b,a.y/b};
}
inline double dis(node x,node y){
return (double)sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
}
inline double dot(node x,node y){
return x.x*y.x+x.y*y.y;
}
inline double cross(node x,node y){
return x.x*y.y-x.y*y.x;
}
inline void Andrew(){
sort(a+1,a+n+1);
stacki[++top]=1;stacki[++top]=2;
for(int i=3;i<=n;i++){
while(top>=2&&cross(a[stacki[top]]-a[stacki[top-1]],a[i]-a[stacki[top]])<=0)--top;
stacki[++top]=i;
}
int tmp=top;
stacki[++top]=n-1;
for(int i=n-2;i>=1;i--){
while(top>tmp&&cross(a[stacki[top]]-a[stacki[top-1]],a[i]-a[stacki[top]])<=0)--top;
stacki[++top]=i;
}
/*cout<<"stacki"<<endl;//
for(int i=1;i<=top;i++)cout<<stacki[i]<<" ";cout<<endl;//
cout<<"array stacki[i] "<<endl;//
for(int i=1;i<=top;i++)cout<<i<<" "<<a[stacki[i]].x<<" "<<a[stacki[i]].y<<endl;//*/
}
inline void find(){
stacki[top+1]=stacki[1];
double ans=1e50;
int h,l,r;
h=l=r=2;
for(int i=2;i<=top;i++){
while(cross(a[stacki[h]]-a[stacki[i]],a[stacki[i-1]]-a[stacki[i]])<=
cross(a[stacki[h%top+1]]-a[stacki[i]],a[stacki[i-1]]-a[stacki[i]]))h=h%top+1;
while(dot(a[stacki[r]]-a[stacki[i]],a[stacki[i-1]]-a[stacki[i]])>=
dot(a[stacki[r%top+1]]-a[stacki[i]],a[stacki[i-1]]-a[stacki[i]]))r=r%top+1;
if(i==2)l=h;
while(dot(a[stacki[l]]-a[stacki[i-1]],a[stacki[i]]-a[stacki[i-1]])>=
dot(a[stacki[l%top+1]]-a[stacki[i-1]],a[stacki[i]]-a[stacki[i-1]]))l=l%top+1;
double len=dis(a[stacki[i]],a[stacki[i-1]]);
double L=dot(a[stacki[l]]-a[stacki[i]],a[stacki[i-1]]-a[stacki[i]])/len;
double R=dot(a[stacki[r]]-a[stacki[i-1]],a[stacki[i]]-a[stacki[i-1]])/len;
double H=cross(a[stacki[i]]-a[stacki[h]],a[stacki[i-1]]-a[stacki[h]])/len;
L=fabs(L);R=fabs(R);H=fabs(H);
double now=(L+R-len)*H;
//cout<<i<<" "<<i-1<<" L "<<L<<" R "<<R<<" H "<<H<<" len "<<len<<" area "<<now<<" l "<<l<<" r "<<r<<" h "<<h<<endl;
if(now<ans){
ans=now;
fin[1]=a[stacki[i]]-(a[stacki[i]]-a[stacki[i-1]])*(L/len);
fin[2]=fin[1]+(a[stacki[i]]-a[stacki[i-1]])*((L+R-len)/len);
fin[3]=fin[2]+(a[stacki[r]]-fin[2])*(H/dis(a[stacki[r]],fin[2]));
fin[4]=fin[3]+(a[stacki[i-1]]-a[stacki[i]])*((L+R-len)/len);
}
}
printf("%.5lf\n",ans);
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].y;
Andrew();find();
int start=0;fin[0].y=1e9,fin[0].x=1e9;
for(int i=1;i<=4;i++)if(fin[i].y<fin[start].y||(fin[i].y==fin[start].y&&fin[i].x<fin[start].x))start=i;
for(int i=0;i<=3;i++){
int x=(start+i)%4;
if(!x)x=4;
if(fabs(fin[x].x)<=1e-8)fin[x].x=0.0;
if(fabs(fin[x].y)<=1e-8)fin[x].y=0.0;
printf("%.5lf %.5lf\n",fin[x].x,fin[x].y);
}
return 0;
}
4.2最小圆覆盖
实际上和旋转卡壳并没有什么关系,但是因为信号塔这一题旋转卡壳+凸包+模拟退火写崩了让我很不爽,所以放在这里。
已知圆的标准方程为 \((x-x_0)^2+(y-y_0)^2=r^2\) ,设 \(P_1=(x_1,y_1)\) ,\(P_2=(x_2,y_2)\) ,\(P_3=(x_3,y_3)\) 。
则
设 \(a=x_1-x_2\) , \(b=y_1-y_2\) , \(c=x_1-x_3\) , \(d=y_1-y_3\) ,
\(e=\frac{(x_1^2-x_2^2)-(y_2^2-y_1^2)}{2}\) ,
\(f=\frac{(x_1^2-x_3^2)-(y_3^2-y_1^2)}{2}\) 。
random_shuffle
https://blog.csdn.net/u010296599/article/details/58596814
https://www.luogu.com.cn/problem/P1742
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=5e5+10;
const double eps=1e-12;
int n;
double R;
struct node{
double x,y;
}a[N],O;
inline double dis(node x,node y){
return (double)sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
}
inline void find(node p1,node p2,node p3){
//实验1号:目的:验证式子是否正确
double a=p1.x-p2.x,b=p1.y-p2.y;
double c=p1.x-p3.x,d=p1.y-p3.y;
double e=(p1.x*p1.x-p2.x*p2.x)-(p2.y*p2.y-p1.y*p1.y);e/=2.0;
double f=(p1.x*p1.x-p3.x*p3.x)-(p3.y*p3.y-p1.y*p1.y);f/=2.0;
O.x=(f*b-e*d)/(c*b-a*d);
O.y=(e*c-f*a)/(c*b-a*d);
R=dis(O,p1);
}
inline void Circle(){
random_shuffle(a+1,a+n+1);
O=a[1];R=0.0;
for(int i=2;i<=n;i++)if(dis(O,a[i])>R+eps){
O=a[i];R=0.0;//枚举圆心
for(int j=1;j<i;j++)if(dis(O,a[j])>R+eps){
O.x=(a[i].x+a[j].x)/2;
O.y=(a[i].y+a[j].y)/2;
R=dis(O,a[j]);//已经确定两个点,两个点连成直线,圆心先放在两个点中点
for(int k=1;k<j;k++)if(dis(O,a[k])>R+eps)
find(a[i],a[j],a[k]);//找到第三个点(在j之前),这个点不在已知的圆内,求三点共圆
}
}
printf("%.10lf\n%.10lf %.10lf",R,O.x,O.y);
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].y;
Circle();
return 0;
}
https://www.luogu.com.cn/problem/P4288
注:把椭圆变成圆进行计算
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=5e4+10;
const double eps=1e-13;
int n;
double R;
struct node{
double x,y;
}a[N],O;
inline double cross(node x,node y){
return x.x*y.y-x.y*y.x;
}
inline double dot(node x,node y){
return x.x*y.x+x.y*y.y;
}
inline double dis(node x,node y){
return (double)sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
}
inline void findCross(node p1,node p2,node p3){
double a=p1.x-p2.x,b=p1.y-p2.y;
double c=p1.x-p3.x,d=p1.y-p3.y;
double e=(p1.x*p1.x-p2.x*p2.x)-(p2.y*p2.y-p1.y*p1.y);e/=2.0;
double f=(p1.x*p1.x-p3.x*p3.x)-(p3.y*p3.y-p1.y*p1.y);f/=2.0;
O.x=(f*b-e*d)/(b*c-a*d);
O.y=(e*c-f*a)/(b*c-a*d);
R=dis(O,p1);
}
inline void Circle(){
random_shuffle(a+1,a+n+1);
O=a[1];R=0.0;
for(int i=2;i<=n;i++)if(dis(O,a[i])>R+eps){
O=a[i];R=0.0;
for(int j=1;j<i;j++)if(dis(O,a[j])>R+eps){
O.x=(a[i].x+a[j].x)/2.0;
O.y=(a[i].y+a[j].y)/2.0;
R=dis(O,a[i]);
for(int k=1;k<j;k++)if(dis(O,a[k])>R+eps)findCross(a[i],a[j],a[k]);
}
}
printf("%.3lf",R);
}
inline node rotate(node x,double theta){
double sini=sin(theta),cosi=cos(theta);
return (node){x.x*cosi-x.y*sini,x.y*cosi+x.x*sini};
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].y;
double theta,p;
cin>>theta>>p;
theta=(360.0-theta)/180.0*acos(-1.0);
p=1.0/p;
for(int i=1;i<=n;i++)a[i]=rotate(a[i],theta);
for(int i=1;i<=n;i++)a[i].x*=p;
Circle();
return 0;
}
5. 半平面交
当我好不容易打完的东西又没了,我的悲伤有亿点大!
5.1 转角公式
设 \(\overrightarrow{AB}\) 从 A 指向 B ,长度为 \(l\) ,A与坐标原点重合,B的坐标为 \((x,y)\) ,角度为 \(\alpha\) ,则 \(l=\sqrt{x^2+y^2}\) 。将 \(\overrightarrow{AB}\) 逆时针旋转 \(\beta\) ,则
旋转前
旋转后
5.2 求向量与x轴夹角
设 \(\overrightarrow{AB}\) 从 A 指向 B ,长度为 \(l\) ,A与坐标原点重合,B的坐标为 \((x,y)\) ,角度为 \(\alpha\) ,则
记得打头文件 #include<cmath> !
5.3 求两直线夹角
设 \(\overrightarrow{a}\) 与 \(\overrightarrow{b}\) 夹角为 \(\theta\) ,两向量形成的平行四边形高为 \(h\) ,高与两断点所连接的两边形成直角三角形,直角三角形两条直角边分别是高 \(h\) 和在 \(\overrightarrow{b}\) 上的底 \(l\) 。
则
5.4 两直线交点
画完图放不上来,放上来还要打好多字,搞不好一不小心typora挂了,啥都没了 。
直接步入正题吧。
5.5 半平面交
https://www.luogu.com.cn/problem/P4196
注:叉乘中两个向量的先后顺序不一样得出来的结果也不一样,毕竟 \(\sin\theta\) 的值有正有负!
https://www.luogu.com.cn/blog/suxxsfe/solution-p4196
https://www.cnblogs.com/xzyxzy/p/10033130.html
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1e5+10;
const double eps=1e-13;//!
int L,R;
struct node{
double x,y;
inline node operator +(const node &b)const{
return (node){x+b.x,y+b.y};
}
inline node operator -(const node &b)const{
return (node){x-b.x,y-b.y};
}
}stain[N],Cross[N];
inline node operator *(node a,double k){
return (node){a.x*k,a.y*k};
}
inline node operator /(node a,double k){
return (node){a.x/k,a.y/k};
}
inline double cross(node x,node y){
return x.x*y.y-x.y*y.x;
}
inline double dot(node x,node y){
return x.x*y.x+x.y*y.y;
}
struct nodei{
node pos,vec;
double angle;
inline void add(node a,node b){//
pos=a;vec=b;
angle=atan2(b.y,b.x);
}
bool operator <(const nodei &b){
return angle<b.angle;
}
}a[N],q[N];
inline int judge(nodei x,node y){
return cross(x.vec,y-x.pos)<=-eps;//判断点y是否在直线x右边
}
inline node findCross(nodei x,nodei y){
node z=x.pos-y.pos;
double t=cross(y.vec,z)/cross(x.vec,y.vec);
return x.pos+x.vec*t;
}
inline double calcArea(int n,node *a){// a:Cross ,求多边形面积
double fin=0.0;
for(int i=1;i<n;i++)fin+=cross(a[i],a[i+1]);
fin+=cross(a[n],a[1]);
fin/=2.0;
return fin;
}
inline int halfPlane(int n){
sort(a+1,a+n+1);
L=R=0;
q[0]=a[1];
for(int i=2;i<=n;i++){
while(L<R&&judge(a[i],Cross[R]))--R;
while(L<R&&judge(a[i],Cross[L+1]))++L;
q[++R]=a[i];
if(fabs(cross(q[R].vec,q[R-1].vec))<=eps){//第R条直线与第R-1条直线平行
if(judge(q[R],q[R-1].pos)&&dot(q[R].vec,q[R-1].vec)<=-eps)return 0;
--R;
if(!judge(q[R],a[i].pos))q[R]=a[i];//在左边
}
if(L<R)Cross[R]=findCross(q[R],q[R-1]);
}
while(L<R&&judge(q[L],Cross[R]))--R;
if(R-L<=1)return 0;//左开右闭区间,当R-L<=1时就只有一条直线
Cross[L]=findCross(q[L],q[R]);
return 1;
}
int main(){
int t,top=0;
cin>>t;
while(t--){
int n;cin>>n;
for(int i=1;i<=n;i++)cin>>stain[i].x>>stain[i].y;
for(int i=1;i<n;i++)a[++top].add(stain[i],stain[i+1]-stain[i]);
a[++top].add(stain[n],stain[1]-stain[n]);
}
if(!halfPlane(top))printf("0.000");
else printf("%.3lf",calcArea(R-L+1,Cross+L-1));
return 0;
}
https://www.luogu.com.cn/problem/P2600
https://www.luogu.com.cn/blog/32768-0x7fffffff/p2600-zjoi2008-wang-ta-ti-xie
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=310;
const double eps=1e-13;
int n,L,R;
struct stain{
double x,y;
bool operator <(const stain &b)const{
return x==b.x?y>b.y:x>b.x;
}
stain operator +(const stain &b)const{
return (stain){x+b.x,y+b.y};
}
stain operator -(const stain &b)const{
return (stain){x-b.x,y-b.y};
}
stain operator *(const double &k)const{
return (stain){x*k,y*k};
}
stain operator /(const double &k)const{
return (stain){x/k,y/k};
}
}a[N],Cross[N];
inline double cross(stain x,stain y){
return x.x*y.y-x.y*y.x;
}
inline double dot(stain x,stain y){
return x.x*y.x+x.y*y.y;
}
struct line{
stain start,endi;
double angle;
bool operator <(const line &b)const{
if(fabs(angle-b.angle)>eps)return angle<b.angle;
else return cross(b.start-start,b.endi-endi)>eps;
}
}p[N],stacki[N];
inline stain findCross(line x,line y){
stain vecx=x.endi-x.start;
stain vecy=y.endi-y.start;
stain vec=y.start-x.start;
double t=cross(vecy,vec)/cross(vecy,vecx);
return x.start+vecx*t;
}
inline void halfPlane(){
sort(p+1,p+n+1);
L=0,R=0;
for(int i=1;i<=n;i++)if(fabs(p[i].angle-p[i-1].angle)>eps||i==1){
/*while(R-L>1&&cross(p[i].endi-p[i].start,Cross[R]-p[i].start)>eps)--R;
while(R-L>1&&cross(p[i].endi-p[i].start,Cross[L+2]-p[i].start)>eps)++L;*/
while(R-L>1&&cross(p[i].endi-Cross[R],p[i].start-Cross[R])>eps)--R;
while(R-L>1&&cross(p[i].endi-Cross[L+2],p[i].start-Cross[L+2])>eps)++L;
stacki[++R]=p[i];
if(R-L>1)Cross[R]=findCross(stacki[R-1],stacki[R]);
}
//while(R-L>1&&cross(stacki[L+1].endi-stacki[L+1].start,Cross[R]-stacki[L+1].start)>eps)--R;
while(R-L>1&&cross(stacki[L+1].endi-Cross[R],stacki[L+1].start-Cross[R])>eps)--R;
//Cross[R+1]=findCross(stacki[L+1],stacki[R]);++R;
}
struct node{
stain start,endi;
double k,b;
bool operator <(const node &x)const{
return start.x<x.start.x;
}
}s[N],t[N];
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i].x;
for(int i=1;i<=n;i++)cin>>a[i].y;
for(int i=1;i<n;i++){
p[i].start=a[i],p[i].endi=a[i+1];
p[i].angle=atan2(a[i+1].y-a[i].y,a[i+1].x-a[i].x);
}
--n;
halfPlane();
//cout<<R-L<<endl;
//cout<<"line"<<endl;//
//for(int i=L+1;i<=R;i++)cout<<i<<" "<<stacki[i].start.x<<" "<<stacki[i].start.y<<" "<<stacki[i].endi.x<<" "<<stacki[i].endi.y<<" "<<stacki[i].angle<<endl;
//cout<<endl;
//cout<<"Cross"<<endl;//
//for(int i=L+2;i<=R;i++)cout<<Cross[i].x<<" "<<Cross[i].y<<endl;
++n;
for(int i=L+1;i<=R;i++){
s[i].start=stacki[i].start;s[i].endi=stacki[i].endi;
s[i].k=(s[i].endi.y-s[i].start.y)/(s[i].endi.x-s[i].start.x);
s[i].b=s[i].start.y-s[i].start.x*s[i].k;
}
for(int i=1;i<n;i++){
t[i].start=a[i];t[i].endi=a[i+1];
t[i].k=(t[i].endi.y-t[i].start.y)/(t[i].endi.x-t[i].start.x);
t[i].b=t[i].start.y-t[i].start.x*t[i].k;
}
//cout<<"s"<<endl;
//for(int i=L+1;i<=R;i++)cout<<s[i].start.x<<" "<<s[i].start.y<<" "<<s[i].endi.x<<" "<<s[i].endi.y<<" "<<s[i].k<<" "<<s[i].b<<endl;
int aim1=1,aim2=L+2;
double ans=1e100;
++R;Cross[R].x=a[n].x;
//cout<<"L "<<L<<" R "<<R<<endl;//
while(aim1<=n&&aim2<=R){
if(a[aim1].x<=Cross[aim2].x){
//cout<<aim1<<" "<<aim2<<" "<<a[aim1].x<<" "<<a[aim1].y<<endl;//
double yi=s[aim2-1].k*a[aim1].x+s[aim2-1].b;
ans=min(ans,fabs(yi-a[aim1].y));
++aim1;
//cout<<aim1<<" "<<aim2<<" "<<fabs(yi-a[aim1-1].y)<<endl;
}else{
//cout<<aim1<<" "<<aim2<<" "<<Cross[aim2].x<<" "<<Cross[aim2].y<<endl;//
double yi=t[aim1-1].k*Cross[aim2].x+t[aim1-1].b;
ans=min(ans,fabs(yi-Cross[aim2].y));
++aim2;
//cout<<aim1<<" "<<aim2<<" "<<fabs(yi-Cross[aim2-1].y)<<endl;//
}
}
printf("%.3lf",ans);
return 0;
}
posted on
浙公网安备 33010602011771号