计算几何整理

整理一些计算几何的东西供自己学习。

旋转卡壳

这篇是本魔芋不负责口胡的,纯属鬼扯。
传送门

半平面交

看代码吧,实在不知道该说啥。
bzoj2618: [Cqoi2006]凸多边形
求凸多边形面积交,半平面交模板题。

关于atan2

atan2(y,x):返回复数x+y*i的辐角,取值(-pi,pi].
用于极角排序,比atan稳定.

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<set>
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
#define Formylove return 0
const int N=20007;
typedef long long LL;
typedef double db;
using namespace std;
int n,k,cnt;
db ans;

template<typename T>void read(T &x) {
	char ch=getchar(); T f=1; x=0;
	while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
	if(ch=='-') f=-1,ch=getchar();
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

#define eps 1e-10
int dcmp(db x) { return fabs(x)<eps?0:(x<0?-1:1); }

struct pt {
	db x,y;
	pt(){}
	pt(db x,db y):x(x),y(y){}
	friend bool operator <(const pt &A,const pt &B) {
		return dcmp(A.x-B.x)<0||(dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)<0);
	}
}p[N];
pt operator +(const pt &A,const pt &B) { return pt(A.x+B.x,A.y+B.y); }
pt operator -(const pt &A,const pt &B) { return pt(A.x-B.x,A.y-B.y); }
pt operator *(const pt &A,const db &B) { return pt(A.x*B,A.y*B); }
pt operator /(const pt &A,const db &B) { return pt(A.x/B,A.y/B); }
db cross(pt A,pt B) { return A.x*B.y-A.y*B.x; }
db dot(pt A,pt B) { return A.x*B.x+A.y*B.y; }

struct Line {
	pt a,b; db slop;
	Line(){}
	Line(pt a,pt b,db slop):a(a),b(b),slop(slop){}
}L[N],que[N];

bool cmp(const Line&A,const Line&B) {
	return dcmp(A.slop-B.slop)<0||(dcmp(A.slop-B.slop)==0&&dcmp(cross(A.b-A.a,B.b-A.a))<0);
}

pt inter(Line A,Line B) {
	db s1=cross(B.b-A.a,A.b-A.a);
	db s2=cross(A.b-A.a,B.a-A.a);
	db t=s1/(s1+s2);
	return B.b+(B.a-B.b)*t;
}

int ck(Line A,Line B,Line C) {
	pt P=inter(A,B);
	return dcmp(cross(P-C.a,C.b-C.a))>=0;
}

db area(int n) {
	db rs=0; p[n+1]=p[1];
	For(i,1,n) rs+=cross(p[i],p[i+1]);
	return fabs(rs)/2.0;
}

db solve(int cnt) {
	int ql=1,qr=0;
	sort(L+1,L+cnt+1,cmp);
	que[++qr]=L[1]; que[++qr]=L[2];
	For(i,3,cnt) {
		while(ql<qr&&ck(que[qr-1],que[qr],L[i])) qr--;
		while(ql<qr&&ck(que[ql+1],que[ql],L[i])) ql++;
		que[++qr]=L[i];
	}
	while(ql+1<qr&&ck(que[qr-1],que[qr],que[ql])) qr--;
	while(ql+1<qr&&ck(que[ql+1],que[ql],que[qr])) ql++;
	que[qr+1]=que[ql];
	int tot=0;
	For(i,ql,qr) p[++tot]=inter(que[i],que[i+1]);
	return area(tot);
}

int main() {
    //freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	read(n);
	For(i,1,n) {
		read(k);
		For(j,1,k) { read(p[j].x); read(p[j].y); }
		p[k+1]=p[1];
		For(j,1,k) L[++cnt]=Line(p[j],p[j+1],atan2(p[j+1].y-p[j].y,p[j+1].x-p[j].x));
	}
	printf("%.3lf\n",solve(cnt));
	Formylove;
}

最小圆覆盖

一个写得非常好的博客
感谢之前汪神教我的这个三点求圆心。
在这里插入图片描述
bzoj2823: [AHOI2012]信号塔
模板题,求圆心和半径。
upd:
如果j到i,k到j而不是j到i-1,k到j-1会WA,精度炸了ORZ。。。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<set>
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
#define Formylove return 0
const int N=500007;
typedef long long LL;
typedef double db;
using namespace std;
int n;
db R;

template<typename T>void read(T &x) {
	char ch=getchar(); T f=1; x=0;
	while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
	if(ch=='-') f=-1,ch=getchar();
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

#define eps 1e-15
int dcmp(db x) { return fabs(x)<eps?0:(x<0?-1:1); }

struct pt {
	db x,y;
	pt(){}
	pt(db x,db y):x(x),y(y){}
	friend bool operator <(const pt &A,const pt &B) {
		return dcmp(A.x-B.x)<0||(dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)<0);
	}
}p[N],O;
pt operator +(const pt &A,const pt &B) { return pt(A.x+B.x,A.y+B.y); }
pt operator -(const pt &A,const pt &B) { return pt(A.x-B.x,A.y-B.y); }
pt operator *(const pt &A,const db &B) { return pt(A.x*B,A.y*B); }
pt operator /(const pt &A,const db &B) { return pt(A.x/B,A.y/B); }
db cross(pt A,pt B) { return A.x*B.y-A.y*B.x; }
db dot(pt A,pt B) { return A.x*B.x+A.y*B.y; }
db lenth(pt A) { return dot(A,A); }

pt get_circle_center(pt A,pt B,pt C) {
	pt c=B-A,b=C-A,t;
	db l1=lenth(c)/2,l2=lenth(b)/2;
	t.x=(l1*b.y-l2*c.y)/(c.x*b.y-b.x*c.y);
	t.y=(l1*b.x-l2*c.x)/(c.y*b.x-b.y*c.x);
	return A+t;
}

void min_circle_cover(int n,pt &c,db &r) {
	random_shuffle(p+1,p+n+1);
	c=p[1],r=0;
	For(i,2,n) if(dcmp(lenth(p[i]-c)-r)>0) {
		c=p[i],r=0;
		For(j,1,i-1) if(dcmp(lenth(p[j]-c)-r)>0) {
			c=(p[i]+p[j])/2,r=lenth(p[i]-c);
			For(k,1,j-1) if(dcmp(lenth(p[k]-c)-r)>0) {
				c=get_circle_center(p[i],p[j],p[k]);
				r=lenth(p[i]-c);
			}
		}
	}
}

int main() {
    //freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	srand(332748118);
	read(n);
	For(i,1,n) scanf("%lf%lf",&p[i].x,&p[i].y);
	min_circle_cover(n,O,R);
	printf("%.2lf %.2lf %.2lf\n",O.x,O.y,sqrt(R));
	Formylove;
}

平面最近点对

HDU-1007 Quoit Design
模板题,求平面最近点对,分治。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<queue>
#include<cmath>
const int N=1e5+7;
typedef long long LL;
typedef double db;
using namespace std;
int T,n;

template<typename T>void read(T &x)  {
    char ch=getchar(); x=0; T f=1;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

struct pt {
    db x,y;
}p[N],tp[N];

bool cmp(const pt&A,const pt&B) { return A.x<B.x||(A.x==B.x&&A.y<B.y); }
bool cmpy(const pt&A,const pt&B) { return A.y<B.y; }
db sqr(db x) {return x*x;}
db dis(pt A,pt B) { return sqrt(sqr(A.x-B.x)+sqr(A.y-B.y)); }

db solve(int l,int r) {
    db d=1e18;
    if(l>=r) return d;
    if(l+1==r) return dis(p[l],p[r]);
    int mid=((l+r)>>1);
    d=min(d,solve(l,mid)); 
    d=min(d,solve(mid+1,r));
    int k=0;
    for(int i=l;i<=r;i++) 
        if(fabs(p[i].x-p[mid].x)<=d) tp[++k]=p[i];
    sort(tp+1,tp+k+1,cmpy);
    for(int i=1;i<=k;i++) 
        for(int j=i+1;j<=k&&tp[j].y-tp[i].y<d;j++) 
            d=min(d,dis(tp[i],tp[j]));
    return d;
}

int main() {
#ifdef DEBUG
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
#endif
    for(;;) {
        read(n);
        if(!n) break;
        for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
        sort(p+1,p+n+1,cmp);
        printf("%.2lf\n",solve(1,n)/2);
    }
    return 0;
}

三维凸包

一个写得非常好的博客
luogu模板

//Achen
#include<bits/stdc++.h>
#define For(i,a,b) for(register int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(register int i=(a);i>=(b);i--)
#define Formylove return 0
const int N=2019;
typedef long long LL;
typedef double db;
using namespace std;
int n,tot;

template<typename T> void read(T &x) {
	char ch=getchar(); T f=1; x=0;
	while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
	if(ch=='-') f=-1,ch=getchar();
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

#define eps 1e-10
int dcmp(db x) { return fabs(x)<eps?0:(x>0?1:-1); }
db Rand() { return (rand()/(db)RAND_MAX-0.5)*eps; }

struct vc {
	db x,y,z;
	vc(){}
	vc(db x,db y,db z):x(x),y(y),z(z){}
	void shake() { x+=Rand(); y+=Rand(); z+=Rand(); }
}v[N];
vc operator +(const vc&A,const vc&B) { return vc(A.x+B.x,A.y+B.y,A.z+B.z); }
vc operator -(const vc&A,const vc&B) { return vc(A.x-B.x,A.y-B.y,A.z-B.z); }
vc cross(vc A,vc B) { return vc(A.y*B.z-A.z*B.y,A.z*B.x-A.x*B.z,A.x*B.y-A.y*B.x); }
db dot(vc A,vc B) { return A.x*B.x+A.y*B.y+A.z*B.z; }
db lenth(vc A) { return sqrt(dot(A,A)); }

struct face {
	int a[3];
	vc normal() { return cross(v[a[1]]-v[a[0]],v[a[2]]-v[a[0]]); }
	db area() { return lenth(normal())/2.0; }
}f[N],tpf[N];

bool cansee(face fc,vc b) { return dot(b-v[fc.a[0]],fc.normal())>0; }

bool vis[N][N],ok;
void get_3D_ham(int n) {
	f[++tot]=(face){1,2,3};
	f[++tot]=(face){3,2,1};
	For(i,4,n) {
		int cc=0;
		For(j,1,tot) {
			if(!(ok=cansee(f[j],v[i]))) tpf[++cc]=f[j];
			For(k,0,2) vis[f[j].a[k]][f[j].a[(k+1)%3]]=ok;
		}
		For(j,1,tot) For(k,0,2) {
			int a=f[j].a[k],b=f[j].a[(k+1)%3];
			if(vis[a][b]&&!vis[b][a]) tpf[++cc]=(face){a,b,i};
		}
		For(j,1,cc) f[j]=tpf[j]; tot=cc;
	}
}

int main() {
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    read(n);
    For(i,1,n) {
		scanf("%lf %lf %lf",&v[i].x,&v[i].y,&v[i].z);
		v[i].shake();
	}
    get_3D_ham(n);
    db ans=0;
	For(i,1,tot) 
		ans+=f[i].area(); 
    printf("%.3lf\n",ans);
	//cerr<<clock()<<endl;
	Formylove;
}

Pick定理、欧拉公式和圆的反演

我是可爱的传送门
poj2954Triangle(pick定理)

关于圆的小模板

两圆面积交

poj2546Circular Area
vjudge传送门
求两圆的面积交。余弦定理求角度,正弦定理求面积。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#define For(i,a,b) for(register int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(register int i=(a);i>=(b);i--)
#define Formylove return 0
#define pi acos(-1.0)
const int N=2019;
typedef long long LL;
typedef double db;
using namespace std;
int n,k;

template<typename T> void read(T &x) {
	char ch=getchar(); T f=1; x=0;
	while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
	if(ch=='-') f=-1,ch=getchar();
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

#define eps 1e-10
int dcmp(db x) { return fabs(x)<eps?0:(x<0?-1:1); }

struct pt {
	db x,y;
	pt(){}
	pt(db x,db y):x(x),y(y){}
	friend bool operator <(const pt &A,const pt &B) {
		return dcmp(A.x-B.x)<0||(dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)<0);
	}
}p[N];
pt operator +(const pt &A,const pt &B) { return pt(A.x+B.x,A.y+B.y); }
pt operator -(const pt &A,const pt &B) { return pt(A.x-B.x,A.y-B.y); }
pt operator *(const pt &A,const db &B) { return pt(A.x*B,A.y*B); }
pt operator /(const pt &A,const db &B) { return pt(A.x/B,A.y/B); }
db cross(pt A,pt B) { return A.x*B.y-A.y*B.x; }
db dot(pt A,pt B) { return A.x*B.x+A.y*B.y; }
db lenth(pt A) { return sqrt(dot(A,A)); }

struct circle {
	pt o; db r;
	friend bool operator <(const circle&A,const circle&B) {
		return A.r<B.r;
	}
	void read() { scanf("%lf%lf%lf",&o.x,&o.y,&r); }
}C1,C2;

db get_inter_area(circle A,circle B) {
	db d=lenth(A.o-B.o);
	if(dcmp(d)==0||dcmp(d-(A.r-B.r))<=0) return B.r*B.r*pi;
	if(dcmp(d-(A.r+B.r))>=0) return 0;
	db theta1=acos((A.r*A.r+d*d-B.r*B.r)/(2.0*A.r*d));
	db theta2=acos((B.r*B.r+d*d-A.r*A.r)/(2.0*B.r*d));
	return A.r*A.r*theta1+B.r*B.r*theta2-A.r*A.r*sin(theta1*2.0)/2.0-B.r*B.r*sin(theta2*2.0)/2.0;
}

int main() {
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
	C1.read(); C2.read();
	if(C1<C2) swap(C1,C2);
	printf("%.3lf\n",get_inter_area(C1,C2));
	Formylove;
}

圆的交点

UVA - 10969 Sweet Dream
读入n个圆r,x,y,后面的圆会覆盖前面的,求最终可以看到的边长。
求出每个圆和它后面的圆的交点,排序,考虑每两个点之间的弧能否看到,若这段弧的中点被它之后的圆覆盖,则看不到,否则能看到。注意特判圆内部,还有弧度统一到(0,2pi].
求交点用的余弦公式和反三角函数,误差较大但好写。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#define For(i,a,b) for(register int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(register int i=(a);i>=(b);i--)
#define Formylove return 0
#define pi acos(-1.0)
const int N=2019;
typedef long long LL;
typedef double db;
using namespace std;
int T,n,no[N];

template<typename T> void read(T &x) {
	char ch=getchar(); T f=1; x=0;
	while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
	if(ch=='-') f=-1,ch=getchar();
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

#define eps 1e-10
int dcmp(db x) { return fabs(x)<eps?0:(x<0?-1:1); }

struct pt {
	db x,y;
	pt(){}
	pt(db x,db y):x(x),y(y){}
	friend bool operator <(const pt &A,const pt &B) {
		return dcmp(A.x-B.x)<0||(dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)<0);
	}
}p[N];
pt operator +(const pt &A,const pt &B) { return pt(A.x+B.x,A.y+B.y); }
pt operator -(const pt &A,const pt &B) { return pt(A.x-B.x,A.y-B.y); }
pt operator *(const pt &A,const db &B) { return pt(A.x*B,A.y*B); }
pt operator /(const pt &A,const db &B) { return pt(A.x/B,A.y/B); }
db cross(pt A,pt B) { return A.x*B.y-A.y*B.x; }
db dot(pt A,pt B) { return A.x*B.x+A.y*B.y; }
db lenth(pt A) { return sqrt(dot(A,A)); }

struct circle {
	pt o; db r;
	friend bool operator <(const circle&A,const circle&B) {
		return A.r<B.r;
	}
	void read() { scanf("%lf%lf%lf",&r,&o.x,&o.y); }
}C[N];
vector<db>vc[N],yvc[N];
db mo(db x) { return x<0?x+pi*2.0:(x>=pi*2.0?x-pi*2:x); }

void get_circle_inter(int id,circle A,circle B) {
	db d=lenth(A.o-B.o);
	if(dcmp(d)==0||dcmp(d-fabs(A.r-B.r))<=0) {
		if(dcmp(B.r-A.r)>=0) no[id]=1;
		return;
	}
	if(dcmp(d-(A.r+B.r))>=0) return ;
	db theta=acos((A.r*A.r+d*d-B.r*B.r)/(2.0*A.r*d));
	db bs=atan2(B.o.y-A.o.y,B.o.x-A.o.x);
	vc[id].push_back(mo(bs-theta));
	vc[id].push_back(mo(bs+theta));
	//return A.r*A.r*theta1+B.r*B.r*theta2-A.r*A.r*sin(theta1*2.0)/2.0-B.r*B.r*sin(theta2*2.0)/2.0;
}

int main() {
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
	read(T);
	while(T--) {
		db ans=0;
		read(n);
		For(i,1,n) C[i].read(),no[i]=0,vc[i].clear(),yvc[i].clear();
		Rep(i,n,1) {
			For(j,i+1,n) get_circle_inter(i,C[i],C[j]);
			int up=vc[i].size();
			if(no[i]) continue;
			if(up==0) ans+=pi*C[i].r*2.0;
			else {
				For(j,0,up-1) 
					yvc[i].push_back(vc[i][j]);
				sort(vc[i].begin(),vc[i].end());
				For(j,0,up-1) {
					db l=vc[i][j],r=vc[i][(j+1)%up];
					if(j==up-1) r+=2.0*pi;
					db md=mo((l+r)/2.0);
					int fl=1;
					for(int k=0;k<up;k+=2) {
						db ll=yvc[i][k],rr=yvc[i][k+1];
						if(rr<ll) rr+=2.0*pi;
						if((dcmp(md-ll)>=0&&dcmp(md-rr)<=0)||(dcmp(md+2.0*pi-ll)>=0&&dcmp(md+2.0*pi-rr)<=0)) {
							fl=0; break;
						}
					}
					if(fl) ans+=2.0*C[i].r*pi*(r-l)/(2.0*pi);
				}
			}
		}
		printf("%.3lf\n",ans);
	}
	Formylove;
}

两圆的公切线

UVA - 10674 Tangents
没搞清楚输出格式wa了好久。。重合时输出-1,没有时输出0。。。
注释在代码里,画图易看出。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#define For(i,a,b) for(register int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(register int i=(a);i>=(b);i--)
#define Formylove return 0
#define pi acos(-1.0)
const int N=2019;
typedef long long LL;
typedef double db;
using namespace std;
int T,cnt;

template<typename T> void read(T &x) {
	char ch=getchar(); T f=1; x=0;
	while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
	if(ch=='-') f=-1,ch=getchar();
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

#define eps 1e-10
int dcmp(db x) { return fabs(x)<eps?0:(x<0?-1:1); }

struct pt {
	db x,y;
	pt(){}
	pt(db x,db y):x(x),y(y){}
	friend bool operator ==(const pt &A,const pt &B) { return dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)==0; }
	friend bool operator <(const pt &A,const pt &B) { return dcmp(A.x-B.x)<0||(dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)<0); }
}p[N];
pt operator +(const pt &A,const pt &B) { return pt(A.x+B.x,A.y+B.y); }
pt operator -(const pt &A,const pt &B) { return pt(A.x-B.x,A.y-B.y); }
pt operator *(const pt &A,const db &B) { return pt(A.x*B,A.y*B); }
pt operator /(const pt &A,const db &B) { return pt(A.x/B,A.y/B); }
db cross(pt A,pt B) { return A.x*B.y-A.y*B.x; }
db dot(pt A,pt B) { return A.x*B.x+A.y*B.y; }
db lenth(pt A) { return sqrt(dot(A,A)); }

struct Line {
	pt a,b;
	Line(){}
	Line(pt a,pt b):a(a),b(b){}
	friend bool operator <(const Line&A,const Line&B) { return A.a<B.a||(A.a==B.a&&A.b<B.b); }
	void out() {
		printf("%.5lf %.5lf %.5lf %.5lf %.5lf\n",a.x,a.y,b.x,b.y,lenth(a-b)); 
	}
}L[N];

struct circle {
	pt o; db r;
	friend bool operator <(const circle&A,const circle&B) { return A.r<B.r; }
	void read() { scanf("%lf%lf%lf",&o.x,&o.y,&r); }
	pt get(db t) { return pt(o.x+r*cos(t),o.y+r*sin(t)); }
}C1,C2;

void get_circle_inter(circle A,circle B) {
	int fl=1; 
	if(A<B) swap(A,B),fl=0;
	db d=lenth(A.o-B.o);
	if(dcmp(d)==0&&dcmp(A.r-B.r)==0) { cnt=-1; return ; }
	if(dcmp(d-(A.r-B.r))<0) return; //内含,无切线
	db bs=atan2(B.o.y-A.o.y,B.o.x-A.o.x);
	if(dcmp(d-(A.r-B.r))==0) { //内切,一条切线 
		pt x=A.get(bs),y=B.get(bs);
		L[++cnt]=fl?Line(x,y):Line(y,x); return;
	} 
	db th=acos((A.r-B.r)/d); //两条外切线 
	pt x=A.get(bs+th),y=B.get(bs+th);
	L[++cnt]=fl?Line(x,y):Line(y,x);
	x=A.get(bs-th),y=B.get(bs-th);
	L[++cnt]=fl?Line(x,y):Line(y,x);
	if(dcmp(d-(A.r+B.r))==0) { //外切,里面一条切线 
		x=A.get(bs),y=B.get(bs+pi);
		L[++cnt]=fl?Line(x,y):Line(y,x);
	}
	else if(dcmp(d-(A.r+B.r))>0) { //外离,里面两条切线 
		th=acos((A.r+B.r)/d);
		x=A.get(bs+th),y=B.get(bs+th+pi);
		L[++cnt]=fl?Line(x,y):Line(y,x);
		x=A.get(bs-th),y=B.get(bs-th+pi);
		L[++cnt]=fl?Line(x,y):Line(y,x);
	} 
}

int main() {
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
	for(;;) {
		C1.read(); C2.read();
		if(C1.o.x==0&&C1.o.y==0&&C1.r==0&&C2.o.x==0&&C2.o.y==0&&C2.r==0) break;
		cnt=0;
		get_circle_inter(C1,C2);
		printf("%d\n",cnt);
		if(!cnt||cnt==-1) continue;
		sort(L+1,L+cnt+1); 
		For(i,1,cnt) L[i].out();
	}
	Formylove;
}

圆的反演

具体见上方“Pick定理、欧拉公式和圆的反演”
HDU - 4773 Problem of Apollonius
给定两相离圆和圆外一点,求过该点的与两外两圆相切的圆。
反演不改变相切关系,不过点的圆反演后为圆,不过点的直线反演后为过点的圆,那么把两圆按该点以任意半径反演后,求两圆的切线,再把切线反演回圆即得答案。
圆关于圆的反演,直线关于圆的反演和公切线的模板。

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#define For(i,a,b) for(register int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(register int i=(a);i>=(b);i--)
#define Formylove return 0
#define pi acos(-1.0)
const int N=2019;
typedef long long LL;
typedef double db;
using namespace std;
int T,cnt,tot;

template<typename T> void read(T &x) {
	char ch=getchar(); T f=1; x=0;
	while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
	if(ch=='-') f=-1,ch=getchar();
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

#define eps 1e-10
int dcmp(db x) { return fabs(x)<eps?0:(x<0?-1:1); }

struct pt {
	db x,y;
	pt(){}
	pt(db x,db y):x(x),y(y){}
	friend bool operator ==(const pt &A,const pt &B) { return dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)==0; }
	friend bool operator <(const pt &A,const pt &B) { return dcmp(A.x-B.x)<0||(dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)<0); }
	void read() { scanf("%lf%lf",&x,&y); }
}sp;
pt operator +(const pt &A,const pt &B) { return pt(A.x+B.x,A.y+B.y); }
pt operator -(const pt &A,const pt &B) { return pt(A.x-B.x,A.y-B.y); }
pt operator *(const pt &A,const db &B) { return pt(A.x*B,A.y*B); }
pt operator /(const pt &A,const db &B) { return pt(A.x/B,A.y/B); }
db cross(pt A,pt B) { return A.x*B.y-A.y*B.x; }
db dot(pt A,pt B) { return A.x*B.x+A.y*B.y; }
db lenth(pt A) { return sqrt(dot(A,A)); }

struct Line {
	pt a,b;
	Line(){}
	Line(pt a,pt b):a(a),b(b){}
	friend bool operator <(const Line&A,const Line&B) { return A.a<B.a||(A.a==B.a&&A.b<B.b); }
	void out() {
		printf("%.5lf %.5lf %.5lf %.5lf %.5lf\n",a.x,a.y,b.x,b.y,lenth(a-b)); 
	}
}L[N];

db node_to_line(pt A,Line B) {
	return fabs(cross(A-B.a,B.b-B.a))/lenth(B.b-B.a);
}

pt foot(pt A,Line B) {
	if(B.a.x==B.b.x) return pt(B.a.x,A.y);
	if(B.a.y==B.b.y) return pt(A.x,B.a.y);
	db k1=(B.a.y-B.b.y)/(B.a.x-B.b.x),k2=-1.0/k1,b=B.a.y-k1*B.a.x;
	db x=(k2*A.x-A.y+b)/(k2-k1),y=k1*x+b;
	return pt(x,y);
}

struct circle {
	pt o; db r;
	friend bool operator <(const circle&A,const circle&B) { return A.r<B.r; }
	pt get(db t) { return pt(o.x+r*cos(t),o.y+r*sin(t)); }
	void read() { scanf("%lf%lf%lf",&o.x,&o.y,&r); }
	void out() { printf("%lf %lf %lf\n",o.x,o.y,r); }
}C1,C2,C1f,C2f,ansC[N];

void get_circle_inter(circle A,circle B) {
	int fl=1; 
	if(A<B) swap(A,B),fl=0;
	db d=lenth(A.o-B.o);
	if(dcmp(d)==0&&dcmp(A.r-B.r)==0) { cnt=-1; return ; }
	if(dcmp(d-(A.r-B.r))<0) return; //内含,无切线
	db bs=atan2(B.o.y-A.o.y,B.o.x-A.o.x);
	if(dcmp(d-(A.r-B.r))==0) { //内切,一条切线 
		pt x=A.get(bs),y=B.get(bs);
		L[++cnt]=fl?Line(x,y):Line(y,x); return;
	} 
	db th=acos((A.r-B.r)/d); //两条外切线 
	pt x=A.get(bs+th),y=B.get(bs+th);
	L[++cnt]=fl?Line(x,y):Line(y,x);
	x=A.get(bs-th),y=B.get(bs-th);
	L[++cnt]=fl?Line(x,y):Line(y,x);
	if(dcmp(d-(A.r+B.r))==0) { //外切,里面一条切线 
		x=A.get(bs),y=B.get(bs+pi);
		L[++cnt]=fl?Line(x,y):Line(y,x);
	}
	else if(dcmp(d-(A.r+B.r))>0) { //外离,里面两条切线 
		th=acos((A.r+B.r)/d);
		x=A.get(bs+th),y=B.get(bs+th+pi);
		L[++cnt]=fl?Line(x,y):Line(y,x);
		x=A.get(bs-th),y=B.get(bs-th+pi);
		L[++cnt]=fl?Line(x,y):Line(y,x);
	}
}

circle get_circle_inv(circle A,circle P) {
	circle rs;
	db d=lenth(A.o-P.o),dmi=d+A.r,dmx=d-A.r;
	dmi=P.r*P.r/dmi; dmx=P.r*P.r/dmx;
	rs.o=P.o+(A.o-P.o)*((dmx+dmi)/2.0/d);
	rs.r=(dmx-dmi)/2.0;
	return rs;
}

circle get_line_inv(Line A,circle P) {
	circle rs;
	pt ft=foot(P.o,A);
	if(ft==P.o) { rs.r=0; return rs; } 
	db d=lenth(P.o-ft),dmx=P.r*P.r/d;
	rs.o=P.o+(ft-P.o)*(dmx/d);
	rs.o=(rs.o+P.o)/2;
	rs.r=lenth(P.o-rs.o);
	return rs;
}

void ck(circle C) {
	if(C.r==0) return ;
	if(dcmp(lenth(sp-C.o)-C.r)!=0) return ;
	if(dcmp(lenth(C.o-C1.o)-C.r-C1.r)!=0) return ;
	if(dcmp(lenth(C.o-C2.o)-C.r-C2.r)!=0) return ;
	ansC[++tot]=C;
}

int main() {
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
	read(T);
	while(T--) {
		C1.read(); C2.read(); sp.read();
		circle P; P.o=sp; P.r=5.0;
		C1f=get_circle_inv(C1,P);
		C2f=get_circle_inv(C2,P);
		cnt=tot=0;
		get_circle_inter(C1f,C2f);
		For(i,1,cnt) ck(get_line_inv(L[i],P));
		printf("%d\n",tot);
		For(i,1,tot) ansC[i].out();
	}
	Formylove;
}

自适应辛普森

传送门

floyd传递闭包

bzoj1027: [JSOI2007]合金
因为x+y+z=1,直接把每个三元组看成前两元为坐标的点
两块合金能合成的点在他们的线段上
n块合金能合成的点在他们构成的凸包内。
题目转换为给定m个点,求一个点数最少的凸包,使n个指定点都在凸包内。
若所有的n个点都在向量i,j的左侧,则 f [ i ] [ j ] = 1 f[i][j]=1 f[i][j]=1,floyd求得最小的 f [ i ] [ i ] f[i][i] f[i][i]即答案。
特判一个点和两个点的凸包。

当只需要判断连通性的时候可以用bitset优化floyd传递闭包。

For(k,1,n) For(i,1,n) For(j,1,n) 
	f[i][j]|=(f[i][k]&f[k][j]);

bitset即:

For(k,1,n) For(i,1,n) if(f[i][k])
	f[i]|=f[k];

合金代码:

//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<cmath>
#define For(i,a,b) for(register int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(register int i=(a);i>=(b);i--)
#define Formylove return 0
const int N=507;
typedef long long LL;
typedef double db;
using namespace std;
int n,m;

template<typename T> void read(T &x) {
    char ch=getchar(); T f=1; x=0;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}

#define eps 1e-7
int dcmp(db x) { return fabs(x)<eps?0:(x>0?1:-1); }

struct pt {
	db x,y;
	pt(){}
	pt(db x,db y):x(x),y(y){}
	friend bool operator <(const pt&A,const pt&B) {
		return A.x<B.x||(A.x==B.x&&A.y<B.y);
	}
	void read() { scanf("%lf%lf",&x,&y); }
}p[N],q[N];
pt operator -(const pt&A,const pt&B) { return pt(A.x-B.x,A.y-B.y); }
db cross(pt A,pt B) { return A.x*B.y-A.y*B.x; }

int f[N][N];

int main() {
    freopen("1027.in","r",stdin);
    freopen("1027.out","w",stdout);
 	read(m); read(n);
 	db nouse;
 	For(i,1,m) { p[i].read(); cin>>nouse; }
 	For(i,1,n) { q[i].read(); cin>>nouse; }
 	if(m==1) {
 		For(i,1,n) if(q[i].x!=p[1].x||q[i].y!=p[1].y) {
 			puts("-1");
 			Formylove;
 		}
 		puts("1"); Formylove;
 	}
   	For(i,1,m) For(j,1,m) {
   		if(i==j) { f[i][j]=m+1; continue; }
   		int ok=1;
   		For(k,1,n) if(dcmp(cross(p[j]-p[i],q[k]-p[i]))<0) {
   			ok=0; break;
   		}
   		f[i][j]=ok?1:m+1;
   	}
   	For(k,1,m) For(i,1,m) For(j,1,m) 
   		f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
   	int ans=m+1;
   	For(i,1,m) ans=min(ans,f[i][i]);
    if(ans==m+1) ans=-1;
    if(ans==2) {
    	db l=1e9,r=-1e9;
    	For(i,1,m) For(j,1,m) if(f[i][j]==1&&f[j][i]==1) {
    		l=min(min(l,p[i].x),p[j].x);
    		r=max(max(r,p[i].x),p[j].x);
    	}
    	For(i,1,n) if(dcmp(q[i].x-l)<0||dcmp(q[i].x-r)>0) {
    		puts("-1");
 			Formylove;
 		}
    }
    printf("%d\n",ans);
    Formylove;
}

平面图转对偶图

我是传送门

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值