计算几何入门。。。
计算几何入门
入门题目:1490 : Master ☆ Spark
超级无敌刁难压轴题,浪费了我很多时间(还是没做出来);
#include <bits/stdc++.h>
using namespace std;
const double eps=1e-8;
const double PI=acos(-1);
int sgn(double number,double eps=1e-8)
{
if(fabs(number)<eps){
return 0;
}else{
return number>0?1:-1;
}
}
class Point;
double Cross(Point p1,Point p2);
double Dot(Point p1,Point p2);
double Getlen(Point var);
double Getlen2(Point var);
struct Point{
//向量
double x;
double y;
double angle;
Point(double xx=0,double yy=0):x(xx),y(yy){
double X=acos(xx/sqrt(xx*xx+yy*yy));
double Y=asin(yy/sqrt(xx*xx+yy*yy));
if(xx){
if( Y>0 )angle=X;
else angle=2*PI-X;
}else{
if( Y>0 )angle=X;
else angle=2*PI-X;
}
}
void operator+=(Point p){x+=p.x,y+=p.y;}
void operator-=(Point p){x-=p.x,y-=p.y;}
void operator*=(int factor){x*=factor,y*=factor;}
void operator/=(int factor){x/=factor,y/=factor;}
void operator*=(double factor){x*=factor,y*=factor;}
void operator/=(double factor){x/=factor,y/=factor;}
friend Point operator+(Point p1,Point p2){return Point(p1.x+p2.x,p1.y+p2.y);}
friend Point operator-(Point p1,Point p2){return Point(p1.x-p2.x,p1.y-p2.y);}
friend Point operator*(Point p1,double factor){return Point(p1.x*factor,p1.y*factor);}
friend Point operator*(double factor,Point p1){return Point(p1.x*factor,p1.y*factor);}
friend Point operator/(Point p1,double factor){return Point(p1.x/factor,p1.y/factor);}
Point Rotate(double rad){return Point(x*cos(rad)-y*sin(rad),x*sin(rad)+y*cos(rad));}
Point Normal(){return Point(-y,x);}
friend double Cross(Point p1,Point p2){return p1.x*p2.y-p2.x*p1.y;}
friend double Dot(Point p1,Point p2){return p1.x*p2.x+p2.y*p1.y;}
friend double Getlen(Point var){return sqrt(Dot(var,var));}
friend double Getlen2(Point var){return Dot(var,var);}
friend Getangle(Point var,Point STD){
double X=acos(Dot(STD,var)/Getlen(var));
double Y=asin(Cross(STD,var)/Getlen(var));
if( Y>0 ){
return X;
}else{
return 2*PI-X;
}
}
bool operator<(const Point&x)const{
return angle<x.angle;
}
};
bool OnSegment(Point p, Point a1, Point a2){
return sgn(Cross(a1-p, a2-p)) == 0 && sgn(Dot(a1-p, a2-p)) < 0;
}
bool isCross(Point& a ,Point& b ,Point& c ,Point&d);
Point Cross_Point(Point& a ,Point& b ,Point& c ,Point&d);
struct Line{
Point p1;
Point p2;
Point Dir;
double A,B,C;
Line(){;}
Line(Point p1,Point p2):p1(p1),p2(p2){A=p1.y-p2.y,B=p2.x-p1.x,C=Cross(p1,p2);if(p1.x>p2.x)swap(p1,p2);Dir=p2-p1;}
Line(double a,double b,double c){
if( !sgn(a) ){
p1=Point(0,-c/b);
p2=Point(1,-c/b);
}else if( !sgn(b) ){
p1=Point(-c/a,0);
p2=Point(-c/a,1);
}else{
p1=Point(0,-c/b);
p2=Point(1,-(-c-a)/b);
}
}
Line Parallel_move(double w){
Point temp=Dir.Normal()/Getlen(Dir);
return Line( p1+w*temp,p2+w*temp );
}
// Line Verdict_move(double w){Point temp=Dir.Normal()/Getlen(Dir.Normal()); return Line( p1+w*temp,p2+w*temp );}
friend bool isCross(Point& a ,Point& b ,Point& c ,Point&d){
double c1=Cross(b-a,c-a),c2=Cross(b-a,d-a);
double d1=Cross(d-c,a-c),d2=Cross(d-c,b-c);
if( !sgn(c1) || !sgn(c2) || !sgn(d1) || !sgn(d2) ){
bool f1 = OnSegment(c, a, b);
bool f2 = OnSegment(d, a, b);
bool f3 = OnSegment(a, c, d);
bool f4 = OnSegment(b, c, d);
bool f = (f1|f2|f3|f4);
return f;
}else{
return sgn(c1)*sgn(c2)<0 && sgn(d1)*sgn(d2)<0;
}
}
friend bool isCross(Line& l1,Line& l2){
return isCross(l1.p1,l1.p2,l2.p1,l2.p2);
}
friend Point Cross_Point(Point& a ,Point& b ,Point& c ,Point&d){
double s1=Cross(b-a,c-a);
double s2=Cross(b-a,d-a);
if( sgn(s1-s2) )
return Point( (c.x*s2-d.x*s1),(c.y*s2-d.y*s1) )/(s2-s1);
else
return Point(DBL_MAX,DBL_MAX);
}
friend Point Cross_Point(Line& l1,Line& l2){
return Cross_Point(l1.p1,l1.p2,l2.p1,l2.p2);
}
friend double dis(Line l,Point p){return fabs(Dot(l.Dir.Normal(),p)/Getlen(l.Dir.Normal()));}
};
struct node{
int number;Point P[300];Line L[300];
Point Heavy_Point;
node(){;}
void Build();
double getArea();
node Cut(Line&cutter);
} tot,sec1,sec2,ret;
void node::Build()
{
sort(P+1,P+1+number);
for(int i=1;i<number;i++){
L[i+number]=L[i]=Line(P[i],P[i+1]);
}
L[number<<1]=L[number]=Line(P[number],P[1]);
}
node node::Cut(Line&cutter)
{
int st=-1,ed=-1;
for(int i=1;i<=number;i++){
if( isCross(cutter,L[i]) ){
if(st==-1){
st=i;
}else{
ed=i;
break;
}
}
}
if(~st && ~ed){
//决定遍历顺序
double delt=P[st].angle-P[ed].angle;
if(delt<0)
delt=P[ed].angle-P[st].angle;
int& cnnt=ret.number;
cnnt=0;
ret.Heavy_Point.x=ret.Heavy_Point.y=0;
if(delt>PI){
ret.Heavy_Point+=(ret.P[++cnnt]=Cross_Point(cutter,L[st]));
for(int i=ed+1;i<=number+st;i++){
ret.Heavy_Point+=(ret.P[++cnnt]=P[i]);
}
ret.Heavy_Point+=(ret.P[++cnnt]=Cross_Point(cutter,L[ed]));
}else{
ret.Heavy_Point+=(ret.P[++cnnt]=Cross_Point(cutter,L[st]));
for(int i=st+1;i<=ed;i++){
ret.Heavy_Point+=(ret.P[++cnnt]=P[i]);
}
ret.Heavy_Point+=(ret.P[++cnnt]=Cross_Point(cutter,L[ed]));
}
ret.Heavy_Point+=(ret.P[++cnnt]=Cross_Point(cutter,L[st]));
ret.Heavy_Point+=(ret.P[++cnnt]=Cross_Point(cutter,L[ed]));
ret.Heavy_Point/=cnnt;
ret.Build();
}
return ret;
}
double node::getArea()
{
double ret=0;
for(int i=1;i<number;i++){
ret+=fabs( Cross(P[i]-Heavy_Point,P[i+1]-Heavy_Point) );
}
ret+=fabs( Cross(P[number]-Heavy_Point,P[1]-Heavy_Point) );
return ret/2;
}
int main()
{
// Point var1(1,-sqrt(3));
// Point var1(1,-1);
// cout<<Getangle( var1,Point(1,0) );
// cout<<Getlen(var1);
// Line l1(1,1,0),l2(1,-1,2);
// Point var=Cross_Point(l1,l2);
// cout<<var.x<<' '<<var.y<<'\n';
// node var;
// cout<<var.getArea();
int n;cin>>n;
tot.number=n;
for(int i=1;i<=n;i++){
double x,y;
cin>>x>>y;
tot.P[i]=Point(x,y);
tot.Heavy_Point+=tot.P[i];
}
tot.Heavy_Point/=n;
tot.Build();
double w,px,py,fx,fy;
cin>>w>>px>>py>>fx>>fy;
Line cutter(Point(px,py),Point(fx,fy));
Line cutter1(cutter.Parallel_move(w/2));
cutter1.p1-=cutter1.Dir*1000;
cutter1.p2+=cutter1.Dir*1000;
Line cutter2(cutter.Parallel_move(-w/2));
cutter2.p1-=1000*cutter2.Dir;
cutter2.p2+=1000*cutter2.Dir;
if( dis(cutter1,tot.Heavy_Point)<=w/2 || dis(cutter2,tot.Heavy_Point)<=w/2 ){
sec1=tot.Cut(cutter1);
sec2=tot.Cut(cutter2);
cout<<fixed;
cout<<setprecision(6)<<100-floor(( ( sec1.getArea()+sec2.getArea() )*100000000 )/(tot.getArea()) )/1000000<<endl;
}else{
cout<<"100.000000"<<endl;
}
return 0;
}
没有规划的学习就是纯摆,浪费时间。
入门题单:
OIer分享
LUOGU
VJ——WORKBOOK
计算几何题的特点与做题要领:
1.大部分不会很难,少部分题目思路很巧妙
2.做计算几何题目,模板很重要,模板必须高度可靠。
3.要注意代码的组织,因为计算几何的题目很容易上两百行代码,里面大部分是模 板。如果代码一片混乱,那么会严重影响做题正确率。
4.注意精度控制。能用整数的地方尽量用整数,要想到扩大数据的方法(扩大一倍, 或扩大sqrt2)。因为整数不用考虑浮点误差,而且运算比浮点快。
会更新的板子:
#include<bits/stdc++.h>
using namespace std;
const double EPS=1e-8;
const double PI=acos(-1);
int sgn(double number,double eps=1e-8){if(fabs(number)<eps)return 0;else return number>0?1:-1;}
struct Point{
double x;
double y;
double angle;
Point() {;}
Point(double vx,double vy):x(vx),y(vy){double theta=acos(x/sqrt(x*x+y*y)) , temp=asin(y/sqrt(x*x+y*y));angle=temp>0?theta:2*PI-theta; }
friend Point operator+(Point p1,Point p2){return Point(p1.x+p2.x,p1.y+p2.y);}
friend Point operator-(Point p1,Point p2){return Point(p1.x-p2.x,p1.y-p2.y);}
friend Point operator*(Point var,double factor){return Point(var.x*factor,var.y*factor);}
friend Point operator*(double factor,Point var){return Point(var.x*factor,var.y*factor);}
friend Point operator/(Point var,double factor){return Point(var.x/factor,var.y/factor);}
void operator+=(Point &var){x+=var.x,y+=var.y;}
void operator-=(Point &var){x-=var.x,y-=var.y;}
void operator*=(Point &var){x*=var.x,y*=var.y;}
void operator/=(Point &var){x/=var.x,y/=var.y;}
};
struct Line {
//点向式
Point p1,p2,Dir;
double A,B,C;
bool isSegment;
Line() {;}
Line(Point vp1,Point vp2,bool Seg=0):p1(vp1),p2(vp2),isSegment(Seg){if(p1.x>p2.x)swap(p1,p2);Dir=p2-p1;A=p2.y-p1.y,B=p1.x-p2.x,C=-(p1.x*p2.y-p2.x*p1.y);}
Line(double a,double b,double c,bool Seg=0):A(a),B(b),C(c),isSegment(Seg){if( !sgn(a) ){ p1=Point(0,-c/b),p2=Point(1,-c/b);}else if( !sgn(b) ) {p1=Point(-c/a,0),p2=Point(-c/a,1);}else {p1=Point(0,-c/b),p2=Point(1,(-a-c)/b);}}
};
#define Segment Line
struct Circle {
Point center;
double r;
Circle(){;}
Circle(double vx,double vy,double vr):center(vx,vy),r(vr) {;}
Circle(Point var,double vr):center(var),r(vr) {;}
};
namespace Calgeo {
double Getdot(Point p1,Point p2){return (p1.x*p2.x+p1.y*p2.y);}
double Getcross(Point p1,Point p2){return (p1.x*p2.y-p1.y*p2.x);}
double Getlen(Point var){return sqrt(var.x*var.x+var.y*var.y);}
double Getlen2(Point var){return var.x*var.x+var.y*var.y;}
double Getlen(Point p1,Point p2){return Getlen(p1-p2);}
double Getlen2(Point p1,Point p2){return Getlen2(p1-p2);}
//单位法向量
Point Normal(Point var){return Point(-var.y,var.x)/Getlen(var);}
double Getangle(Point p1,Point p2){return acos(Getdot(p1,p2));}
double Getdis(Point p1,Point p2) {return Getlen(p1-p2);}
double Getdis(Line l,Point p) {return fabs(Getcross(l.p1-p,Normal(l.Dir))) ;}
double Getdis(Circle c,Point p) {return Getdis(p,c.center);}
double Getdis(Line l,Circle c) {return Getdis(l,c.center);}
double Getproj(Line l,Point p) {return fabs(Getdot(p,l.Dir)) ;}
bool Isparallel(Point p1,Point p2){return p1.angle==p2.angle;}
bool Isparallel(Line l1,Line l2){return Isparallel(l1.Dir,l2.Dir);}
bool Iscross(Point a,Point b,Point c,Point d){double c1=Getcross(b-a,d-a),c2=Getcross(b-a,c-a),d1=Getcross(d-c,b-c),d2=Getcross(d-c,a-c);return sgn(c1)*sgn(c2)<0 && sgn(d1)*sgn(d2)<0 ;}
bool IscrossEdge(Point a,Point b,Point c,Point d){double c1=Getcross(b-a,d-a),c2=Getcross(b-a,c-a),d1=Getcross(d-c,b-c),d2=Getcross(d-c,a-c);return sgn(c1)*sgn(c2)<=0 && sgn(d1)*sgn(d2)<=0 ;}
int Cnt_Crosspoint(Line l,Circle c){double temp=Getdis(l,c);if(temp>c.r)return 0;else if(temp==c.r)return 1;else return 2;}
// int Cnt_Crosspoint(Line l1,Line l2){if(Isparallel(l1,l2)){return 0;}else if(l1.isSegment){}else if(l2.isSegment){}else{} ;}
Point Getcrosspoint(Point a,Point b,Point c,Point d){double s1=Getcross(b-a,c-a),s2=Getcross(b-a,d-a);return Point(c.x*s2-d.x*s1,c.y*s2-d.y*s1)/(s2-s1);}
Point Getcrosspoint(Line l1,Line l2){return Getcrosspoint(l1.p1,l1.p2,l2.p1,l2.p2);}
// Point Getcrosspoint(Line l,Circle c){;}
}
using namespace Calgeo;
signed main(void)
{
return 0;
}
总结起来就是,一股脑地写了很多东西,以为自己懂很多。事实上这些计算几何的内容里面很多都是高中数学的向量、平面几何、立体几何、解析几何的内容,大学高数又教了很多东西。所以学起来不痛苦。
但是要注意时间啊!浪费了很多时间但是却没有什么收获,学这个是为了AC率和思维,其他的什么快感放一边去。
浙公网安备 33010602011771号