计算几何作业(上)

好多HDU的题,我想死。

HDU 6325 Problem G. Interstellar Travel

求从左到右字典序最小上凸壳,注意这个题不能选多个重点。
A C   C o d e \mathcal AC \ Code AC Code

#include
#define maxn 200005
#define LL long long
#define Ct const
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;

int n;

#define Pt Point
struct Pt{
	LL x,y;
	Pt(Ct LL &x=0,Ct LL &y=0):x(x),y(y){}
	Pt operator +(Ct Pt &B)Ct{ return Pt(x + B.x , y + B.y); }
	Pt operator -(Ct Pt &B)Ct{ return Pt(x - B.x , y - B.y); }
	LL operator *(Ct Pt &B)Ct{ return x * B.y - y * B.x; }
}P[maxn];
int c[maxn];
bool cmp(const int &u,const int &v){ return P[u].x == P[v].x ? P[u].y > P[v].y : P[u].x < P[v].x; }
int q[maxn],R;

int main(){
	int T;
	for(scanf("%d",&T);T--;){
		scanf("%d",&n);
		rep(i,1,n) scanf("%lld%lld",&P[i].x,&P[i].y),c[i]=i;
		stable_sort(c+1,c+1+n,cmp);
		q[R=0] = 1; 
		rep(i,2,n){
			int u=c[i];
			if(P[u].x == P[c[i-1]].x && P[u].y == P[c[i-1]].y) 
				continue;
			for(;R>=1 && (
				(P[q[R]] - P[q[R-1]]) * (P[u] - P[q[R-1]]) > 0 
				||
				((P[q[R]] - P[q[R-1]]) * (P[u] - P[q[R-1]]) == 0 && u < q[R]) 
				)
				;)
				R--;
			q[++R] = u;
		}
		rep(i,0,R) printf("%d%c",q[i]," \n"[i==R]);
	}
}

HDU 2202 最大三角形

n n n个点中选三个点的最大三角形面积。
首先存在一个最大三角形三个点都在凸包上。
求出凸包后有 O ( n 2 ) O(n^2) O(n2)的旋转卡壳和 O ( n 3 ) O(n^3) O(n3)的暴力枚举算法。
但是他们都能过。
这是因为这道题有一个性质是 x , y ∈ N ∧ − 1 e 4 ≤ x , y ≤ 1 e 4 x,y \in \N \wedge -1e4 \leq x , y \leq 1e4 x,yN1e4x,y1e4
C = 1 e 4 C = 1e4 C=1e4
有一个结论就是凸包上的点数上界是 O ( C 2 3 ) O(C^\frac 23) O(C32)(期望点数是 O ( log ⁡ C ) O(\log C) O(logC)的)
首先很多构造凸包的想法都是 O ( C 1 2 ) O(C^\frac 12) O(C21)的,
证明思路应该是有效的斜率只有 O ( C 2 3 ) O(C^\frac 23) O(C32)种(具体证明应该和 S t e r n − B r o c o t   T r e e Stern-Brocot\ Tree SternBrocot Tree有关,也就是和最简分数有关其实就是我不会),这是答案的上界。
然后这里给出一个构造:
造一个 x 2 + y 2 ≤ C 2 x^2 + y^2 \leq C^2 x2+y2C2的圆,把圆内所有顶点造个凸包,容易发现这个凸包的点数就是 O ( n 2 3 ) O(n ^ \frac 23) O(n32)级别的。
这东西怎么网上一点提示都没有啊啊啊啊啊啊啊啊啊连CF出题人都敷衍了事这莫非是什么离谱的openproblem吗

A C   C o d e \mathcal AC \ Code AC Code

#include
#define maxn 50005
#define LL long long
#define Ct const
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;

int n;

#define Pt Point
struct Pt{
	LL x,y;
	Pt(Ct LL &x=0,Ct LL &y=0):x(x),y(y){}
	Pt operator +(Ct Pt &B)Ct{ return Pt(x + B.x , y + B.y); }
	Pt operator -(Ct Pt &B)Ct{ return Pt(x - B.x , y - B.y); }
	LL operator *(Ct Pt &B)Ct{ return x * B.y - y * B.x; }
}P[maxn];
int c[maxn];
bool cmp(const int &u,const int &v){ return P[u].x == P[v].x ? P[u].y > P[v].y : P[u].x < P[v].x; }
int q[maxn],R;

int main(){
	//freopen("1.in","r",stdin);
	for(;scanf("%d",&n) != EOF;){
		rep(i,1,n) scanf("%lld%lld",&P[i].x,&P[i].y),c[i]=i;
		stable_sort(c+1,c+1+n,cmp);
		q[R=0] = c[1]; 
		rep(i,2,n){
			int u=c[i];
			for(;R>=1 && ((P[q[R]] - P[q[R-1]]) * (P[u] - P[q[R-1]]) >= 0);)R--;
			q[++R] = u;
		}
		int L = R;
		per(i,n,1){
			int u = c[i];
			for(;R>L && ((P[q[R]] - P[q[R-1]]) * (P[u] - P[q[R-1]]) >= 0);)R--;
			q[++R] = u;
		}
		LL ans = 0;
		rep(i,0,R) rep(j,i+1,R) rep(k,j+1,R)
			ans = max(ans , abs((P[q[j]]-P[q[i]]) * (P[q[k]]-P[q[i]])));
		printf("%.2lf\n",(double)ans / 2);
	}
}

HDU 1392 Surround the Trees

垃圾题目,题意有病,建议出题人审视一下自己的conscience
A C   C o d e \mathcal AC \ Code AC Code

#include
#define maxn 50005
#define LL long long
#define Ct const
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;

int n;
double sqr(double a){ return a * a; }
#define Pt Point
struct Pt{
    LL x,y;
    Pt(Ct LL &x=0,Ct LL &y=0):x(x),y(y){}
    Pt operator +(Ct Pt &B)Ct{ return Pt(x + B.x , y + B.y); }
    Pt operator -(Ct Pt &B)Ct{ return Pt(x - B.x , y - B.y); }
    LL operator *(Ct Pt &B)Ct{ return x * B.y - y * B.x; }
    double dist(Ct Pt &B)Ct{
        return sqrt(sqr(x - B.x) + sqr(y - B.y));
    }
}P[maxn];
int c[maxn];
bool cmp(const int &u,const int &v){ return P[u].x == P[v].x ? P[u].y > P[v].y : P[u].x < P[v].x; }
int q[maxn],R;

int main(){
    //freopen("1.in","r",stdin);
    for(;scanf("%d",&n) != EOF && n;){
        rep(i,1,n) scanf("%lld%lld",&P[i].x,&P[i].y),c[i]=i;
        stable_sort(c+1,c+1+n,cmp);
        q[R=0] = c[1]; 
        rep(i,2,n){
            int u=c[i];
            for(;R>=1 && ((P[q[R]] - P[q[R-1]]) * (P[u] - P[q[R-1]]) >= 0);)R--;
            q[++R] = u;
        }
        int L = R;
        per(i,n,1){
            int u = c[i];
            for(;R>L && ((P[q[R]] - P[q[R-1]]) * (P[u] - P[q[R-1]]) >= 0);)R--;
            q[++R] = u;
        }
        double ans = 0;
        rep(i,0,R-1) ans += P[q[i]].dist(P[q[i+1]]);
        if(n == 2) ans /= 2;
        printf("%.2lf\n",ans);
    }
}

HDU 1469 Video Surveillance

求多边形的核。
注意到Thus the edges alternate between horizontal and vertical.
所以为什么要写半平面交呢?

A C   C o d e \mathcal AC \ Code AC Code

#include
#include
#define maxn 105
#define inf 0x3f3f3f3f
using namespace std;

int n,x[maxn],y[maxn],mnx,mxx,mny,mxy;

int main(){
	int cas = 0;
	while(~scanf("%d",&n) && n){
		for(int i=0;i<n;i++) scanf("%d%d",&x[i],&y[i]);
		mnx = mny = -inf;
		mxx = mxy = inf;
		for(int i=0;i<n;i++){
			int v = (i+1)%n;
			if(x[i] == x[v]){
				if(y[i] > y[v]) mxx = min(mxx , x[i]);
				else mnx = max(mnx , x[i]);
			}
			else{
				if(x[i] < x[v]) mxy = min(mxy , y[i]);
				else mny = max(mny , y[i]);
			}
		}
		printf("Floor #%d\n",++cas);
		if(mnx > mxx || mny > mxy) puts("Surveillance is impossible.");
		else puts("Surveillance is possible.");
		putchar('\n');
	}
}

HDU 5462 Manors

n n n个人,每个人有 m m m个旗子坐标为 x i , j , y i , j x_{i,j},y_{i,j} xi,j,yi,j,求在 409 5 2 4095^2 40952 的土地上每一个点 x , y x,y x,y按照 f i ( x , y ) f_i(x,y) fi(x,y)计算的最小的那个 i i i就是这个位置的主人,求每个人的土地大小。

f i ( x , y ) = m x 2 + m y 2 − 2 x ∑ j x i , j − 2 y ∑ j y i , j + ∑ j x i , j 2 + y i , j 2 f_i(x,y) = mx^2+my^2-2x\sum_{j}x_{i,j}-2y\sum_{j}y_{i,j}+\sum_{j}x_{i,j}^2+y_{i,j}^2 fi(x,y)=mx2+my22xjxi,j2yjyi,j+jxi,j2+yi,j2

f i ( x , y ) − f k ( x , y ) = − 2 ∑ j ( x i , j − x k , j ) x − 2 ∑ j ( y i , j − y k , j ) y + ∑ j ( x i , j 2 + y i , j 2 − x k , j 2 − y k , j 2 ) ≤ 0 f_i(x,y) - f_k(x,y) = -2\sum_{j}(x_{i,j} - x_{k,j})x -2\sum_{j}(y_{i,j}-y_{k,j})y+\sum_{j}(x_{i,j}^2+y_{i,j}^2-x_{k,j}^2-y_{k,j}^2) \leq 0 fi(x,y)fk(x,y)=2j(xi,jxk,j)x2j(yi,jyk,j)y+j(xi,j2+yi,j2xk,j2yk,j2)0
半平面交即可得到面积。

A C   C o d e \mathcal AC \ Code AC Code

#include
#define db double
#define Ct const
#define Pt Point
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define eps 1e-8
#define maxn 205
#define maxm 2005
using namespace std;

int n,m;
db x[maxn][maxm] , y[maxn][maxm] , smx[maxn] , smy[maxn] , smx2[maxn] , smy2[maxn];

int dcmp(Ct db &a){ return a < -eps ? -1 : a > eps ? 1 : 0; }
db sqr(Ct db &a){ return a * a; }
struct Pt{
	db x,y;
	Pt(Ct db &x=0,Ct db &y=0):x(x),y(y){}
	Pt operator +(Ct Pt &B)Ct{ return Pt(x+B.x,y+B.y); }
	Pt operator -(Ct Pt &B)Ct{ return Pt(x-B.x,y-B.y); }
	db operator *(Ct Pt &B)Ct{ return x * B.y - y * B.x; }
	Pt operator *(Ct db &B)Ct{ return Pt(x * B , y * B); }
}qp[maxn];
struct Ln{
	Pt S,T;
	db ang;
	Ln(Ct Pt &S=0,Ct Pt &T=0):S(S),T(T){ ang = atan2(T.y-S.y,T.x-S.x); }
	bool operator <(Ct Ln &B)Ct{ return dcmp(ang - B.ang) ? ang < B.ang : (B.T - S) * (T - S) < 0; }
}L[maxn],q[maxn];
int cnt,ql,qr;

Pt Itp(Ct Pt &p1,Ct Pt &v1,Ct Pt &p2,Ct Pt &v2){ return p1 + v1 * ((p2 - p1) * v2 / (v1 * v2)); }
#define Ptln(a) a.S,a.T-a.S

db HalfPlaneInsection(){
	sort(L+1,L+1+cnt);
	ql=0,qr=-1;
	rep(i,1,cnt) if(i == 1 || dcmp(L[i].ang - L[i-1].ang)){
		for(;ql<=qr-1 && (qp[qr] - L[i].S) * (L[i].T - L[i].S) <= 0;qr--);
		for(;ql<=qr-1 && (qp[ql+1] - L[i].S) * (L[i].T - L[i].S) <= 0;ql++);
		q[++qr] = L[i];
		if(ql<=qr-1) qp[qr] = Itp(Ptln(q[qr]),Ptln(q[qr-1]));
	}
	for(;ql<=qr-2 && (qp[qr] - q[ql].S) * (q[ql].T - q[ql].S) <= 0;qr--);
	if(qr-ql<2) return 0;
	qp[ql] = Itp(Ptln(q[qr]),Ptln(q[ql]));
	db ans = 0;
	rep(i,ql,qr){
		int v = i + 1;
		if(v > qr) v = ql;
		ans += (qp[i] - qp[ql]) * (qp[v] - qp[ql]); 
	}
	return ans / 2;
}

int main(){
	int T,cas=0;
	for(scanf("%d",&T);T--;){
		scanf("%d%d",&n,&m);
		rep(i,1,n) smx[i] = smy[i] = smx2[i] = smy2[i] = 0;
		rep(i,1,n) rep(j,1,m) scanf("%lf%lf",&x[i][j],&y[i][j]) , smx[i] += x[i][j] , smx2[i] += sqr(x[i][j]) , smy[i] += y[i][j] , smy2[i] += sqr(y[i][j]);
		printf("Case #%d: ",++cas);
		rep(i,1,n){
			cnt = 0;
			rep(j,1,n) if(i^j){
				db A=2 * (smx[j] - smx[i]),B=2 * (smy[j] - smy[i]),C=smx2[i] + smy2[i] - smx2[j] - smy2[j];
				Pt S , T;
				if(dcmp(A)) S = Pt(- C / A , 0);
				else S = Pt(0 , -C / B);
				T = S + Pt(B,-A);
				L[++cnt] = Ln(S,T);
			}
			L[++cnt] = Ln(Pt(0,0) , Pt(0,4095));
			L[++cnt] = Ln(Pt(0,4095) , Pt(4095,4095));
			L[++cnt] = Ln(Pt(4095,4095),Pt(4095,0));
			L[++cnt] = Ln(Pt(4095,0),Pt(0,0));
			printf("%d%c",(int)round(HalfPlaneInsection())," \n"[i==n]);
		}
	}
}

HDU 4327 Shooting

[ 0 , 1 ] × [ 0 , 1 ] [0,1]\times [0,1] [0,1]×[0,1]的平面内每个点 ( x , y ) (x,y) (x,y)有个权重 f ( x , y ) = 2 − x − y f(x,y) = 2 - x - y f(x,y)=2xy,平面内有 n n n个点 { p i } \{p_i\} {pi},现在在平面上带权随机选择一个点,问离这个点最近的点是 p i p_i pi的概率。

和上题基本一样,半平面交求出每个点的范围后求积分:
假如是 S ( a , b ) , T ( c , d ) S(a,b),T(c,d) S(a,b),T(c,d),求线段 S → T S\rightarrow T ST下的带权积分。
∫ x = a b ∫ y = 0 c + ( d − c ) ( x − a ) b − a 2 − x − y d x d y \int_{x=a}^b \int_{y=0}^{c + \frac {(d-c)(x-a)}{b-a}} 2-x-y{\rm d}x{\rm d}y x=aby=0c+ba(dc)(xa)2xydxdy
形式不太优美,设 y = k x + B y = kx + B y=kx+B
原式分成三部分:
∫ x = a b ∫ y = 0 k x + B 2 = ( b − a ) ( d + c ) \int_{x=a}^b \int_{y=0}^{kx+B} 2 = (b-a)(d+c) x=aby=0kx+B2=(ba)(d+c)
∫ x = a b − x ∫ y = 0 k x + B 1 = ∫ x = a b − k x 2 − B x = k ( a 3 − b 3 ) 3 + ( a 2 − b 2 ) B 2 \int_{x=a}^b -x \int_{y=0}^{kx+B} 1=\int_{x=a}^b -kx^2-Bx = \frac {k(a^3-b^3)}3 + \frac{(a^2-b^2)B}2 x=abxy=0kx+B1=x=abkx2Bx=3k(a3b3)+2(a2b2)B
− ∫ x = a b ∫ y = 0 k x + B y = − ∫ x = a b k 2 x 2 + B 2 2 + k B x = k 2 ( a 3 − b 3 ) 6 + B 2 ( a − b ) 2 + k B ( a 2 − b 2 ) 2 -\int_{x=a}^b\int_{y=0}^{kx+B} y = -\int_{x=a}^b \frac {k^2x^2+B^2}2+kBx = \frac {k^2(a^3-b^3)}6+\frac {B^2(a-b)}2 + \frac {kB(a^2-b^2)}2 x=aby=0kx+By=x=ab2k2x2+B2+kBx=6k2(a3b3)+2B2(ab)+2kB(a2b2)
然后就硬算即可。

A C   C o d e \mathcal AC \ Code AC Code

#include
#define db double
#define Ct const
#define Pt Point
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define eps 1e-8
#define maxn 205
#define maxm 2005
using namespace std;

int n,m;
db x[maxn],y[maxn];

int dcmp(Ct db &a){ return a < -eps ? -1 : a > eps ? 1 : 0; }
db sqr(Ct db &a){ return a * a; }
db cube(Ct db &a){ return a * a * a; }
struct Pt{
	db x,y;
	Pt(Ct db &x=0,Ct db &y=0):x(x),y(y){}
	Pt operator +(Ct Pt &B)Ct{ return Pt(x+B.x,y+B.y); }
	Pt operator -(Ct Pt &B)Ct{ return Pt(x-B.x,y-B.y); }
	db operator *(Ct Pt &B)Ct{ return x * B.y - y * B.x; }
	Pt operator *(Ct db &B)Ct{ return Pt(x * B , y * B); }
}qp[maxn];
struct Ln{
	Pt S,T;
	db ang;
	Ln(Ct Pt &S=0,Ct Pt &T=0):S(S),T(T){ ang = atan2(T.y-S.y,T.x-S.x); }
	bool operator <(Ct Ln &B)Ct{ return dcmp(ang - B.ang) ? ang < B.ang : (B.T - S) * (T - S) < 0; }
}L[maxn],q[maxn];
int cnt,ql,qr;

Pt Itp(Ct Pt &p1,Ct Pt &v1,Ct Pt &p2,Ct Pt &v2){ return p1 + v1 * ((p2 - p1) * v2 / (v1 * v2)); }
#define Ptln(a) a.S,a.T-a.S

db HalfPlaneInsection(){
	sort(L+1,L+1+cnt);
	ql=0,qr=-1;
	rep(i,1,cnt) if(i == 1 || dcmp(L[i].ang - L[i-1].ang)){
		for(;ql<=qr-1 && (qp[qr] - L[i].S) * (L[i].T - L[i].S) <= 0;qr--);
		for(;ql<=qr-1 && (qp[ql+1] - L[i].S) * (L[i].T - L[i].S) <= 0;ql++);
		q[++qr] = L[i];
		if(ql<=qr-1) qp[qr] = Itp(Ptln(q[qr]),Ptln(q[qr-1]));
	}
	for(;ql<=qr-2 && (qp[qr] - q[ql].S) * (q[ql].T - q[ql].S) <= 0;qr--);
	if(qr-ql<2) return 0;
	qp[ql] = Itp(Ptln(q[qr]),Ptln(q[ql]));
	db ans = 0;
	rep(i,ql,qr){
		int v = i + 1;
		if(v > qr) v = ql;
		if(dcmp(qp[i].x - qp[v].x)){
			db K = (qp[v].y - qp[i].y) / (qp[v].x - qp[i].x) , B = qp[i].y - qp[i].x * K;
			ans += (qp[v].x - qp[i].x) * (qp[v].y + qp[i].y)
				+ K * (cube(qp[i].x) - cube(qp[v].x)) / 3 
				+ B * (sqr(qp[i].x) - sqr(qp[v].x)) / 2
				+ sqr(K) * (cube(qp[i].x) - cube(qp[v].x)) / 6
				+ sqr(B) * (qp[i].x - qp[v].x) / 2
				+ K * B * (sqr(qp[i].x) - sqr(qp[v].x)) / 2;
		}
	}
	return fabs(ans);
}

int main(){
	int T,cas=0;
	for(scanf("%d",&T);T--;){
		scanf("%d",&n);
		rep(i,1,n) scanf("%lf%lf",&x[i],&y[i]);
		printf("Case #%d:\n",++cas);
		rep(i,1,n){
			cnt = 0;
			rep(j,1,n) if(i^j){
				db A=2 * (x[j] - x[i]),B=2 * (y[j] - y[i]),C=sqr(x[i]) + sqr(y[i]) - sqr(x[j]) - sqr(y[j]);
				Pt S , T;
				if(dcmp(A)) S = Pt(- C / A , 0);
				else S = Pt(0 , -C / B);
				T = S + Pt(B,-A);
				L[++cnt] = Ln(S,T);
			}
			L[++cnt] = Ln(Pt(0,0) , Pt(0,1));
			L[++cnt] = Ln(Pt(0,1) , Pt(1,1));
			L[++cnt] = Ln(Pt(1,1),Pt(1,0));
			L[++cnt] = Ln(Pt(1,0),Pt(0,0));
			printf("%.6lf\n",HalfPlaneInsection());
		}
	}
} 	

HDU 6354 Everything Has Changed

用一堆圆来切割一个圆心为原点,半径为R的圆A,问切割完毕后圆A外围剩余部分的周长。

注意到题目中所有圆都只会和大圆 A A A相交,所以直接判断相交后加入大圆被删去的部分加回小圆加入的部分。

C o d e Code Code

#include
#define db double
#define Pi 3.1415926535897932384626433832795
using namespace std;

int m;
db R,x,y,r;
db sqr(db a){ return a * a; }

int main(){
	int T;
	scanf("%d",&T);
	for(;T--;){
		scanf("%d%lf",&m,&R);
		db ans = 2 * Pi * R;
		for(int i=1;i<=m;i++){
			scanf("%lf%lf%lf",&x,&y,&r);
			db d = sqrt(x*x+y*y);
			if(d + r >= R && d - r <= R){
				db a = acos((sqr(d) + sqr(R) - sqr(r)) / d / 2 / R);
				db b = acos((sqr(d) + sqr(r) - sqr(R)) / d / 2 / r);
				ans += b * 2 * r - a * 2 * R;
			}
		}
		printf("%.15lf\n",ans);
	}
}

你可能感兴趣的:(计算几何)